2017-09-29 18:29:36 +01:00
|
|
|
/** Script used in the commandline iframe. Communicates with background. */
|
2017-10-02 00:59:51 +01:00
|
|
|
|
2017-10-05 23:11:56 +01:00
|
|
|
import * as Messaging from './messaging'
|
2017-10-12 04:43:56 +01:00
|
|
|
import * as SELF from './commandline_frame'
|
2017-11-09 08:04:05 +00:00
|
|
|
import './number.clamp'
|
|
|
|
import state from './state'
|
2017-10-05 23:11:56 +01:00
|
|
|
|
2017-10-09 12:09:23 -07:00
|
|
|
let completions = window.document.getElementById("completions") as HTMLElement
|
2017-09-29 18:29:36 +01:00
|
|
|
let clInput = window.document.getElementById("tridactyl-input") as HTMLInputElement
|
2017-10-12 04:02:01 +01:00
|
|
|
|
|
|
|
export let focus = () => clInput.focus()
|
2017-09-29 18:29:36 +01:00
|
|
|
|
2017-10-28 05:11:10 +01:00
|
|
|
async function sendExstr(exstr) {
|
|
|
|
Messaging.message("commandline_background", "recvExStr", [exstr])
|
|
|
|
}
|
|
|
|
|
2017-11-05 14:48:22 +00:00
|
|
|
|
|
|
|
|
2017-09-29 18:29:36 +01:00
|
|
|
/* Process the commandline on enter. */
|
|
|
|
clInput.addEventListener("keydown", function (keyevent) {
|
2017-11-05 14:48:22 +00:00
|
|
|
switch (keyevent.key) {
|
|
|
|
case "Enter":
|
|
|
|
process()
|
|
|
|
break
|
|
|
|
|
|
|
|
case "Escape":
|
|
|
|
hide_and_clear()
|
|
|
|
break
|
|
|
|
|
|
|
|
// Todo: fish-style history search
|
|
|
|
// persistent history
|
|
|
|
case "ArrowUp":
|
|
|
|
history(-1)
|
|
|
|
break
|
|
|
|
|
|
|
|
case "ArrowDown":
|
|
|
|
history(1)
|
|
|
|
break
|
|
|
|
|
|
|
|
// Clear input on ^C
|
|
|
|
// Todo: hard mode: vi style editing on cli, like set -o mode vi
|
|
|
|
// should probably just defer to another library
|
|
|
|
case "c":
|
|
|
|
if (keyevent.ctrlKey) hide_and_clear()
|
2017-11-09 12:44:57 +00:00
|
|
|
break
|
|
|
|
|
|
|
|
case "f":
|
|
|
|
if (keyevent.ctrlKey){
|
|
|
|
// Stop ctrl+f from doing find
|
|
|
|
keyevent.preventDefault()
|
|
|
|
keyevent.stopPropagation()
|
|
|
|
tabcomplete()
|
|
|
|
}
|
|
|
|
break
|
|
|
|
|
|
|
|
case "Tab":
|
|
|
|
// Stop tab from losing focus
|
|
|
|
keyevent.preventDefault()
|
|
|
|
keyevent.stopPropagation()
|
|
|
|
tabcomplete()
|
|
|
|
break
|
2017-11-05 14:48:22 +00:00
|
|
|
|
2017-10-09 12:40:23 -07:00
|
|
|
}
|
2017-09-29 18:29:36 +01:00
|
|
|
})
|
|
|
|
|
2017-11-05 14:48:22 +00:00
|
|
|
let cmdline_history_position = 0
|
|
|
|
let cmdline_history_current = ""
|
|
|
|
|
|
|
|
function hide_and_clear(){
|
2017-11-09 08:04:05 +00:00
|
|
|
/** Bug workaround: clInput cannot be cleared during an "Escape"
|
|
|
|
* keydown event, presumably due to Firefox's internal handler for
|
|
|
|
* Escape. So clear clInput just after :)
|
|
|
|
*/
|
|
|
|
completions.innerHTML = ""
|
|
|
|
setTimeout(()=>{clInput.value = ""}, 0)
|
|
|
|
sendExstr("hidecmdline")
|
2017-11-05 14:48:22 +00:00
|
|
|
}
|
|
|
|
|
2017-11-09 12:44:57 +00:00
|
|
|
function tabcomplete(){
|
|
|
|
let fragment = clInput.value
|
|
|
|
let matches = state.cmdHistory.filter((key)=>key.startsWith(fragment))
|
|
|
|
let mostrecent = matches[matches.length - 1]
|
|
|
|
if (mostrecent != undefined) clInput.value = mostrecent
|
|
|
|
}
|
|
|
|
|
2017-11-05 14:48:22 +00:00
|
|
|
function history(n){
|
|
|
|
completions.innerHTML = ""
|
|
|
|
if (cmdline_history_position == 0){
|
|
|
|
cmdline_history_current = clInput.value
|
|
|
|
}
|
2017-11-09 08:04:05 +00:00
|
|
|
let wrapped_ind = state.cmdHistory.length + n - cmdline_history_position
|
|
|
|
wrapped_ind = wrapped_ind.clamp(0, state.cmdHistory.length)
|
|
|
|
|
|
|
|
const pot_history = state.cmdHistory[wrapped_ind]
|
2017-11-05 14:48:22 +00:00
|
|
|
clInput.value = pot_history == undefined ? cmdline_history_current : pot_history
|
2017-11-09 08:04:05 +00:00
|
|
|
cmdline_history_position = cmdline_history_position - n
|
2017-11-05 14:48:22 +00:00
|
|
|
}
|
|
|
|
|
2017-09-29 18:29:36 +01:00
|
|
|
/* Send the commandline to the background script and await response. */
|
|
|
|
function process() {
|
|
|
|
console.log(clInput.value)
|
2017-10-28 05:11:10 +01:00
|
|
|
sendExstr("hidecmdline")
|
|
|
|
sendExstr(clInput.value)
|
2017-11-09 08:19:28 +00:00
|
|
|
if (! browser.extension.inIncognitoContext) {
|
|
|
|
state.cmdHistory = state.cmdHistory.concat([clInput.value])
|
|
|
|
}
|
2017-11-09 08:04:05 +00:00
|
|
|
console.log(state.cmdHistory)
|
2017-10-13 22:10:33 -07:00
|
|
|
completions.innerHTML = ""
|
2017-09-29 18:29:36 +01:00
|
|
|
clInput.value = ""
|
2017-11-05 14:48:22 +00:00
|
|
|
cmdline_history_position = 0
|
2017-09-29 18:29:36 +01:00
|
|
|
}
|
2017-10-02 00:59:51 +01:00
|
|
|
|
2017-11-09 15:30:09 +00:00
|
|
|
export function fillcmdline(newcommand?: string, trailspace = true){
|
|
|
|
if (newcommand !== "") {
|
|
|
|
if (trailspace) clInput.value = newcommand + " "
|
|
|
|
else clInput.value = newcommand
|
2017-10-06 04:16:02 +01:00
|
|
|
}
|
|
|
|
// Focus is lost for some reason.
|
2017-10-12 04:02:01 +01:00
|
|
|
focus()
|
2017-10-05 23:11:56 +01:00
|
|
|
}
|
|
|
|
|
2017-10-12 04:43:56 +01:00
|
|
|
export function changecompletions(newcompletions: string) {
|
2017-10-09 12:09:23 -07:00
|
|
|
completions.innerHTML = newcompletions
|
|
|
|
}
|
|
|
|
|
2017-10-28 13:42:54 +01:00
|
|
|
function applyWithTmpTextArea(fn) {
|
|
|
|
let textarea
|
|
|
|
try {
|
|
|
|
textarea = document.createElement("textarea")
|
|
|
|
// Scratchpad must be `display`ed, but can be tiny and invisible.
|
|
|
|
// Being tiny and invisible means it won't make the parent page move.
|
|
|
|
textarea.style.cssText = 'visible: invisible; width: 0; height: 0; position: fixed'
|
|
|
|
textarea.contentEditable = "true"
|
|
|
|
document.documentElement.appendChild(textarea)
|
|
|
|
return fn(textarea)
|
|
|
|
} finally {
|
|
|
|
document.documentElement.removeChild(textarea)
|
|
|
|
}
|
2017-10-28 19:20:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
export function setClipboard(content: string) {
|
2017-10-28 13:42:54 +01:00
|
|
|
return applyWithTmpTextArea(scratchpad => {
|
2017-10-28 19:20:31 +08:00
|
|
|
scratchpad.value = content
|
|
|
|
scratchpad.select()
|
2017-10-28 13:42:54 +01:00
|
|
|
if (document.execCommand("Copy")) {
|
|
|
|
// // todo: Maybe we can consider to using some logger and show it with status bar in the future
|
|
|
|
console.log('set clipboard:', scratchpad.value)
|
|
|
|
} else throw "Failed to copy!"
|
2017-10-28 19:20:31 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-10-28 13:42:54 +01:00
|
|
|
export function getClipboard() {
|
|
|
|
return applyWithTmpTextArea(scratchpad => {
|
2017-10-28 19:20:31 +08:00
|
|
|
scratchpad.focus()
|
|
|
|
document.execCommand("Paste")
|
|
|
|
console.log('get clipboard', scratchpad.textContent)
|
2017-10-28 13:42:54 +01:00
|
|
|
return scratchpad.textContent
|
2017-10-28 19:20:31 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-10-28 13:42:54 +01:00
|
|
|
Messaging.addListener('commandline_frame', Messaging.attributeCaller(SELF))
|