2017-10-12 04:02:01 +01:00
// '//#' is a start point for a simple text-replacement-type macro. See excmds_macros.py
2017-11-19 06:05:15 +00:00
/ * * # T r i d a c t y l h e l p p a g e
Use ` :help <excmd> ` or scroll down to show [ [ help ] ] for a particular excmd .
Tridactyl is in a pretty early stage of development . Please report any issues and make requests for missing features on the GitHub project page [ [ 1 ] ] .
Highlighted features :
- Press ` b ` to bring up a list of open tabs in the current window ; you can type the tab ID or part of the title or URL to choose a tab ( the buffer list doesn 't show which one you' ve selected yet , but it does work )
- Press ` I ` to enter ignore mode . ` Shift ` + ` Escape ` to return to normal mode .
- Press ` f ` to start "hint mode" , ` F ` to open in background
- Press ` o ` to ` :open ` a different page
- Press ` s ` if you want to search for something that looks like a domain name or URL
- [ [ bind ] ] new commands with e . g . ` :bind J tabnext `
- Type ` :help ` to see a list of available excmds
- Use ` yy ` to copy the current page URL to your clipboard
- ` ]] ` and ` [[ ` to navigate through the pages of comics , paginated articles , etc
- Pressing ` ZZ ` will close all tabs and windows , but it will only "save" them if your about :preferences are set to "show your tabs and windows from last time"
There are some caveats common to all webextension vimperator - alikes :
- Do not try to navigate to any about : \ * pages using ` :open ` as it will fail silently
- Firefox will not load Tridactyl on addons . mozilla . org , about : \ * , some file : \ * URIs , view - source : \ * , or data : \ * . On these pages Ctrl - L ( or F6 ) , Ctrl - Tab and Ctrl - W are your escape hatches
- Tridactyl does not currently support changing / hiding the Firefox GUI , but you can do it yourself by changing your userChrome . There is an example file available on our repository [ [ 2 ] ]
If you want a more fully - featured vimperator - alike , your best option is Firefox ESR [ [ 3 ] ] and Vimperator : )
[ 1 ] : https : //github.com/cmcaine/tridactyl/issues
[ 2 ] : https : //github.com/cmcaine/tridactyl/blob/master/src/static/userChrome-minimal.css
[ 3 ] : https : //www.mozilla.org/en-US/firefox/organizations/
* /
/** ignore this line */
2017-10-12 04:02:01 +01:00
// {{{ setup
2017-10-23 09:42:50 +01:00
import * as Messaging from "./messaging"
2017-11-15 00:41:53 +00:00
import { l } from './lib/webext'
2017-10-23 09:42:50 +01:00
2017-10-12 04:02:01 +01:00
//#content_omit_line
import * as CommandLineContent from "./commandline_content"
//#content_omit_line
import "./number.clamp"
//#content_helper
import * as SELF from "./excmds_content"
2017-10-23 09:42:50 +01:00
//#content_helper
Messaging . addListener ( 'excmd_content' , Messaging . attributeCaller ( SELF ) )
2017-10-28 05:11:10 +01:00
/** Message excmds_content.ts in the active tab of the currentWindow */
//#background_helper
import { messageActiveTab } from './messaging'
2017-10-12 04:02:01 +01:00
//#background_helper
import "./number.mod"
//#background_helper
import state from "./state"
2017-10-23 09:42:50 +01:00
//#background_helper
2017-11-09 00:41:07 +00:00
import { ModeName } from './state'
//#background_helper
2017-10-23 09:42:50 +01:00
import * as keydown from "./keydown_background"
2017-11-09 00:41:07 +00:00
//#background_helper
import { activeTab , activeTabId } from './lib/webext'
2017-10-12 04:02:01 +01:00
2017-11-03 19:10:12 +00:00
/** @hidden */
2017-10-12 04:02:01 +01:00
//#background_helper
2017-10-23 09:42:50 +01:00
export const cmd_params = new Map < string , Map < string , string > > ( )
2017-10-12 04:02:01 +01:00
2017-11-14 23:31:08 +00:00
const SEARCH_URLS = new Map < string , string > ( [
[ "google" , "https://www.google.com/search?q=" ] ,
[ "googleuk" , "https://www.google.co.uk/search?q=" ] ,
[ "bing" , "https://www.bing.com/search?q=" ] ,
[ "duckduckgo" , "https://duckduckgo.com/?q=" ] ,
[ "yahoo" , "https://search.yahoo.com/search?p=" ] ,
[ "twitter" , "https://twitter.com/search?q=" ] ,
[ "wikipedia" , "https://en.wikipedia.org/wiki/" ] ,
[ "youtube" , "https://www.youtube.com/results?search_query=" ] ,
[ "amazon" , "https://www.amazon.com/s/ref=nb_sb_noss?url=search-alias%3Daps&field-keywords=" ] ,
[ "amazonuk" , "https://www.amazon.co.uk/s/ref=nb_sb_noss?url=search-alias%3Daps&field-keywords=" ] ,
] )
2017-10-22 16:33:43 +01:00
2017-11-03 19:10:12 +00:00
/** @hidden */
2017-10-12 04:02:01 +01:00
function hasScheme ( uri : string ) {
2017-11-19 06:05:15 +00:00
return uri . match ( /^([\w-]+):/ )
2017-10-12 04:02:01 +01:00
}
/** If maybeURI doesn't have a schema, affix http:// */
2017-11-03 19:10:12 +00:00
/** @hidden */
2017-10-12 04:02:01 +01:00
function forceURI ( maybeURI : string ) {
if ( hasScheme ( maybeURI ) ) {
return maybeURI
2017-11-09 07:38:24 +00:00
}
2017-11-15 00:55:51 +02:00
2017-11-09 15:30:09 +00:00
let urlarr = maybeURI . split ( " " )
2017-11-15 00:55:51 +02:00
if ( SEARCH_URLS . get ( urlarr [ 0 ] ) != null ) {
return SEARCH_URLS . get ( urlarr [ 0 ] ) + urlarr . slice ( 1 , urlarr . length ) . join ( " " )
2017-11-09 07:38:24 +00:00
} else if ( urlarr [ 0 ] . includes ( '.' ) ) {
2017-10-12 04:02:01 +01:00
return "http://" + maybeURI
2017-10-22 16:33:43 +01:00
} else {
2017-11-15 00:55:51 +02:00
return SEARCH_URLS . get ( "google" ) + maybeURI
2017-10-12 04:02:01 +01:00
}
}
2017-11-03 19:10:12 +00:00
/** @hidden */
2017-10-12 04:02:01 +01:00
//#background_helper
function tabSetActive ( id : number ) {
browser . tabs . update ( id , { active : true } )
}
// }}}
// {{{ PAGE CONTEXT
2017-11-09 21:01:57 +00:00
/** Blur (unfocus) the active element */
//#content
export function unfocus() {
( document . activeElement as HTMLInputElement ) . blur ( )
}
2017-10-12 04:02:01 +01:00
//#content
export function scrollpx ( a : number , b : number ) {
window . scrollBy ( a , b )
}
/ * * I f o n e a r g u m e n t i s g i v e n , s c r o l l t o t h a t p e r c e n t a g e d o w n t h e p a g e .
If two arguments are given , treat as x and y values to give to window . scrollTo
* /
//#content
export function scrollto ( a : number , b? : number ) {
a = Number ( a )
// if b is undefined, Number(b) is NaN.
b = Number ( b )
window . scrollTo (
b ? a : window.scrollX ,
b
? b
: a . clamp ( 0 , 100 ) *
( window . document . scrollingElement . scrollHeight / 100 )
)
}
//#content
export function scrollline ( n = 1 ) {
window . scrollByLines ( n )
}
//#content
export function scrollpage ( n = 1 ) {
2017-11-07 12:05:14 +00:00
window . scrollBy ( 0 , window . innerHeight * n )
2017-10-12 04:02:01 +01:00
}
2017-11-03 19:10:12 +00:00
/** @hidden */
2017-10-12 04:02:01 +01:00
//#content_helper
function history ( n : number ) {
window . history . go ( n )
}
2017-11-19 06:05:15 +00:00
/** Navigate forward one page in history. */
2017-10-12 04:02:01 +01:00
//#content
export function forward ( n = 1 ) {
history ( n )
}
2017-11-19 06:05:15 +00:00
/** Navigate back one page in history. */
2017-10-12 04:02:01 +01:00
//#content
export function back ( n = 1 ) {
history ( n * - 1 )
}
/** Reload the next n tabs, starting with activeTab, possibly bypassingCache */
//#background
export async function reload ( n = 1 , hard = false ) {
2017-11-09 00:41:07 +00:00
let tabstoreload = await getnexttabs ( await activeTabId ( ) , n )
2017-10-12 04:02:01 +01:00
let reloadProperties = { bypassCache : hard }
tabstoreload . map ( n = > browser . tabs . reload ( n , reloadProperties ) )
}
/** Reload the next n tabs, starting with activeTab. bypass cache for all */
//#background
export async function reloadhard ( n = 1 ) {
reload ( n , true )
}
2017-11-19 06:05:15 +00:00
/ * * O p e n a n e w p a g e i n t h e c u r r e n t t a b .
@param urlarr
- if first word looks like it has a schema , treat as a URI
- else if the first word contains a dot , treat as a domain name
- else if the first word is a key of [ [ SEARCH_URLS ] ] , treat all following terms as search parameters for that provider
- else treat as search parameters for google
* /
2017-10-12 04:02:01 +01:00
//#content
2017-10-22 16:33:43 +01:00
export function open ( . . . urlarr : string [ ] ) {
2017-11-09 15:30:09 +00:00
let url = urlarr . join ( " " )
2017-10-12 04:02:01 +01:00
window . location . href = forceURI ( url )
}
2017-11-19 06:05:15 +00:00
/ * * S h o w t h i s p a g e .
` :help <excmd> ` jumps to the entry for that command .
2017-10-23 23:44:07 +01:00
2017-11-19 06:05:15 +00:00
e . g . ` :help bind `
* /
//#background
export async function help ( excmd? : string ) {
const docpage = browser . extension . getURL ( "static/docs/modules/_excmds_.html#" )
if ( excmd === undefined ) excmd = "tridactyl-help-page"
if ( ( await activeTab ( ) ) . url . startsWith ( docpage ) ) {
open ( docpage + excmd )
} else {
tabopen ( docpage + excmd )
}
2017-10-23 23:44:07 +01:00
}
2017-11-03 19:10:12 +00:00
/** @hidden */
2017-10-12 04:02:01 +01:00
//#content_helper
function getlinks ( ) {
return document . getElementsByTagName ( 'a' )
}
/** Find a likely next/previous link and follow it */
//#content
2017-11-19 06:05:15 +00:00
export function clicknext ( dir : "next" | "prev" = "next" ) {
2017-10-12 04:02:01 +01:00
let linkarray = Array . from ( getlinks ( ) )
let regarray = [ /\bnext|^>$|^(>>|»)$|^(>|»)|(>|»)$|\bmore\b/i , /\bprev\b|\bprevious\b|^<$|^(<<|«)$|^(<|«)|(<|«)$/i ]
regarray = window . location . href . match ( /rockpapershotgun/ ) ? [ /newer/i , /older/i ] : regarray
let nextreg = ( dir == "next" ) ? regarray [ 0 ] : regarray [ 1 ]
// Might need to add more cases to this as we look at more sites
let nextlinks = linkarray . filter ( ( link ) = > ( link . innerText . match ( nextreg ) || link . rel . match ( nextreg ) ) )
// Use the last link that matches because next/prev buttons tend to be at the end of the page
// whereas lots of blogs have "VIEW MORE" etc. plastered all over their pages.
// Stops us from having to hardcode in RPS and reddit, for example.
window . location . href = nextlinks . slice ( - 1 ) [ 0 ] . href
}
2017-11-15 12:40:26 +00:00
//#background
export function zoom ( level = 0 ) {
level = level > 3 ? level / 100 : level
browser . tabs . setZoom ( level )
}
2017-10-12 04:02:01 +01:00
// }}}
// {{{ TABS
/ * * S w i t c h t o t h e n e x t t a b b y i n d e x ( p o s i t i o n o n t a b b a r ) , w r a p p i n g r o u n d .
optional increment is number of tabs forwards to move .
* /
//#background
export async function tabnext ( increment = 1 ) {
// Get an array of tabs in the current window
let current_window = await browser . windows . getCurrent ( )
let tabs = await browser . tabs . query ( { windowId : current_window.id } )
// Derive the index we want
let desiredIndex = ( ( await activeTab ( ) ) . index + increment ) . mod ( tabs . length )
// Find and switch to the tab with that index
2017-10-21 12:54:48 +02:00
let desiredTab = tabs . find ( ( tab : any ) = > {
2017-10-12 04:02:01 +01:00
return tab . index === desiredIndex
2017-10-21 12:54:48 +02:00
} )
2017-10-12 04:02:01 +01:00
tabSetActive ( desiredTab . id )
}
//#background
export function tabprev ( increment = 1 ) {
tabnext ( increment * - 1 )
}
2017-11-19 06:05:15 +00:00
/** Like [[open]], but in a new tab */
2017-10-12 04:02:01 +01:00
//#background
2017-10-24 17:40:00 +01:00
export async function tabopen ( . . . addressarr : string [ ] ) {
2017-10-23 09:42:50 +01:00
let uri
2017-11-09 15:30:09 +00:00
let address = addressarr . join ( ' ' )
2017-10-24 17:40:00 +01:00
if ( address != "" ) uri = forceURI ( address )
2017-10-23 09:42:50 +01:00
browser . tabs . create ( { url : uri } )
2017-10-12 04:02:01 +01:00
}
//#background
export async function tabduplicate ( id? : number ) {
2017-11-09 00:41:07 +00:00
id = id ? id : ( await activeTabId ( ) )
2017-10-12 04:02:01 +01:00
browser . tabs . duplicate ( id )
}
//#background
export async function tabdetach ( id? : number ) {
2017-11-09 00:41:07 +00:00
id = id ? id : ( await activeTabId ( ) )
2017-10-12 04:02:01 +01:00
browser . windows . create ( { tabId : id } )
}
//#background
export async function tabclose ( ids? : number [ ] | number ) {
if ( ids !== undefined ) {
browser . tabs . remove ( ids )
} else {
// Close the current tab
2017-11-09 00:41:07 +00:00
browser . tabs . remove ( await activeTabId ( ) )
2017-10-12 04:02:01 +01:00
}
}
2017-10-21 12:54:48 +02:00
/** restore most recently closed tab in this window unless the most recently closed item was a window */
2017-10-12 04:02:01 +01:00
//#background
export async function undo ( ) {
2017-10-21 12:54:48 +02:00
const current_win_id : number = ( await browser . windows . getCurrent ( ) ) . id
const sessions = await browser . sessions . getRecentlyClosed ( )
// The first session object that's a window or a tab from this window. Or undefined if sessions is empty.
let closed = sessions . find ( ( s ) = > {
2017-10-22 16:32:11 +01:00
return ( 'window' in s || s . tab && ( s . tab . windowId == current_win_id ) )
2017-10-21 12:54:48 +02:00
} )
if ( closed ) {
if ( closed . tab ) {
browser . sessions . restore ( closed . tab . sessionId )
}
else if ( closed . window ) {
browser . sessions . restore ( closed . window . sessionId )
}
}
2017-10-12 04:02:01 +01:00
}
//#background
export async function tabmove ( n? : string ) {
let aTab = await activeTab ( ) ,
m : number
if ( ! n ) {
browser . tabs . move ( aTab . id , { index : - 1 } )
return
} else if ( n . startsWith ( "+" ) || n . startsWith ( "-" ) ) {
m = Math . max ( 0 , Number ( n ) + aTab . index )
} else m = Number ( n )
browser . tabs . move ( aTab . id , { index : m } )
}
2017-11-19 06:05:15 +00:00
/** Pin the current tab */
2017-10-12 04:02:01 +01:00
//#background
export async function pin() {
let aTab = await activeTab ( )
browser . tabs . update ( aTab . id , { pinned : ! aTab . pinned } )
}
// }}}
// {{{ WINDOWS
2017-11-19 06:05:15 +00:00
/** Like [[open]], but in a new window */
2017-10-12 04:02:01 +01:00
//#background
export async function winopen ( . . . args : string [ ] ) {
let address : string
const createData = { }
if ( args [ 0 ] === "-private" ) {
createData [ "incognito" ] = true
2017-11-09 15:30:09 +00:00
address = args . slice ( 1 , args . length ) . join ( ' ' )
} else address = args . join ( ' ' )
2017-11-14 12:23:01 +00:00
createData [ "url" ] = address != "" ? forceURI ( address ) : null
2017-10-12 04:02:01 +01:00
browser . windows . create ( createData )
}
//#background
export async function winclose() {
browser . windows . remove ( ( await browser . windows . getCurrent ( ) ) . id )
}
2017-11-02 19:36:44 +00:00
2017-11-19 06:05:15 +00:00
/** Close all windows */
2017-11-02 19:36:44 +00:00
// It's unclear if this will leave a session that can be restored.
// We might have to do it ourselves.
//#background
export async function qall ( ) {
let windows = await browser . windows . getAll ( )
windows . map ( ( window ) = > browser . windows . remove ( window . id ) )
}
2017-10-12 04:02:01 +01:00
// }}}
// {{{ MISC
2017-11-19 06:05:15 +00:00
/** Deprecated */
2017-10-23 09:42:50 +01:00
//#background
export function suppress ( preventDefault? : boolean , stopPropagation? : boolean ) {
2017-11-19 03:22:59 +00:00
mode ( "ignore" )
2017-10-23 09:42:50 +01:00
}
2017-11-19 06:05:15 +00:00
/ * * E x a m p l e :
- ` mode ignore ` to ignore all keys .
* /
2017-10-12 04:02:01 +01:00
//#background
2017-11-09 00:41:07 +00:00
export function mode ( mode : ModeName ) {
2017-11-19 06:05:15 +00:00
// TODO: event emition on mode change.
2017-11-19 07:57:30 +00:00
if ( mode === "hint" ) {
2017-11-19 06:05:15 +00:00
hint ( )
} else {
state . mode = mode
}
2017-10-12 04:02:01 +01:00
}
2017-11-19 06:05:15 +00:00
//#background_helper
async function getnexttabs ( tabid : number , n? : number ) {
2017-10-12 04:02:01 +01:00
const curIndex : number = ( await browser . tabs . get ( tabid ) ) . index
const tabs : browser.tabs.Tab [ ] = await browser . tabs . query ( {
currentWindow : true ,
} )
const indexFilter = ( ( tab : browser.tabs.Tab ) = > {
return (
curIndex <= tab . index &&
( n ? tab . index < curIndex + Number ( n ) : true )
)
} ) . bind ( n )
return tabs . filter ( indexFilter ) . map ( ( tab : browser.tabs.Tab ) = > {
return tab . id
} )
}
// Moderately slow; should load in results as they arrive, perhaps
// Todo: allow jumping to buffers once they are found
// Consider adding to buffers with incremental search
// maybe only if no other results in URL etc?
// Find out how to return context of each result
//#background
/* export async function findintabs(query: string) { */
/* const tabs = await browser.tabs.query({currentWindow: true}) */
/* console.log(query) */
/* const findintab = async tab => */
/* await browser.find.find(query, {tabId: tab.id}) */
/* let results = [] */
/* for (let tab of tabs) { */
/* let result = await findintab(tab) */
/* if (result.count > 0) { */
/* results.push({tab, result}) */
/* } */
/* } */
/* results.sort(r => r.result.count) */
/* console.log(results) */
/* return results */
/* } */
// }}}
// {{{ CMDLINE
2017-11-18 13:47:10 +00:00
//#background_helper
import * as controller from './controller'
2017-11-19 06:05:15 +00:00
/ * * S p l i t ` c m d s ` o n p i p e s ( | ) a n d t r e a t e a c h a s i t ' s o w n c o m m a n d .
2017-11-18 13:47:10 +00:00
2017-11-19 06:05:15 +00:00
Workaround : this should clearly be in the parser , but we haven ' t come up with a good way to deal with | s in URLs , search terms , etc . yet .
2017-11-18 13:47:10 +00:00
* /
//#background
export function composite ( . . . cmds : string [ ] ) {
cmds = cmds . join ( " " ) . split ( "|" )
cmds . forEach ( controller . acceptExCmd )
}
2017-11-19 06:05:15 +00:00
/** Don't use this */
2017-10-12 04:02:01 +01:00
// TODO: These two don't really make sense as excmds, they're internal things.
//#content
export function showcmdline() {
CommandLineContent . show ( )
2017-10-28 13:42:54 +01:00
CommandLineContent . focus ( )
2017-10-12 04:02:01 +01:00
}
2017-11-19 06:05:15 +00:00
/** Don't use this */
2017-10-12 04:02:01 +01:00
//#content
export function hidecmdline() {
CommandLineContent . hide ( )
2017-10-28 19:20:31 +08:00
CommandLineContent . blur ( )
2017-10-12 04:02:01 +01:00
}
2017-11-19 06:05:15 +00:00
/** Set the current value of the commandline to string *with* a trailing space */
2017-10-12 04:02:01 +01:00
//#background
2017-10-24 12:51:04 +01:00
export function fillcmdline ( . . . strarr : string [ ] ) {
let str = strarr . join ( " " )
2017-10-12 04:02:01 +01:00
showcmdline ( )
2017-10-28 05:11:10 +01:00
messageActiveTab ( "commandline_frame" , "fillcmdline" , [ str ] )
2017-10-12 04:02:01 +01:00
}
2017-11-19 06:05:15 +00:00
/** Set the current value of the commandline to string *without* a trailing space */
2017-11-09 15:30:09 +00:00
//#background
export function fillcmdline_notrail ( . . . strarr : string [ ] ) {
let str = strarr . join ( " " )
let trailspace = false
showcmdline ( )
messageActiveTab ( "commandline_frame" , "fillcmdline" , [ str , trailspace ] )
}
2017-11-19 06:05:15 +00:00
/ * * E q u i v a l e n t t o ` f i l l c m d l i n e _ n o t r a i l < y o u r a r g s > < c u r r e n t U R L > `
See also [ [ fillcmdline_notrail ] ]
* /
2017-11-09 15:30:09 +00:00
//#background
export async function current_url ( . . . strarr : string [ ] ) {
2017-11-09 15:30:09 +00:00
fillcmdline_notrail ( . . . strarr , ( await activeTab ( ) ) . url )
2017-11-09 15:30:09 +00:00
}
2017-11-19 06:05:15 +00:00
/ * * U s e t h e s y s t e m c l i p b o a r d .
If ` excmd == "open" ` , call [ [ open ] ] with the contents of the clipboard . Similarly for [ [ tabopen ] ] .
If ` excmd == "yank" ` , copy the current URL , or if given , the value of toYank , into the system clipboard .
Unfortunately , javascript can only give us the ` clipboard ` clipboard , not e . g . the X selection clipboard .
* /
2017-10-28 19:20:31 +08:00
//#background
2017-11-19 06:05:15 +00:00
export async function clipboard ( excmd : "open" | "yank" | "tabopen" = "open" , . . . toYank : string [ ] ) {
let content = toYank . join ( " " )
2017-11-16 19:58:33 +00:00
let url = ""
2017-10-28 19:20:31 +08:00
switch ( excmd ) {
case 'yank' :
2017-10-28 13:42:54 +01:00
await messageActiveTab ( "commandline_content" , "focus" )
2017-11-04 17:30:34 +00:00
content = ( content == "" ) ? ( await activeTab ( ) ) . url : content
messageActiveTab ( "commandline_frame" , "setClipboard" , [ content ] )
2017-10-28 19:20:31 +08:00
break
case 'open' :
2017-10-28 13:42:54 +01:00
await messageActiveTab ( "commandline_content" , "focus" )
2017-11-16 19:58:33 +00:00
url = await messageActiveTab ( "commandline_frame" , "getClipboard" )
url && open ( url )
break
case 'tabopen' :
await messageActiveTab ( "commandline_content" , "focus" )
url = await messageActiveTab ( "commandline_frame" , "getClipboard" )
url && tabopen ( url )
2017-10-28 19:20:31 +08:00
break
default :
// todo: maybe we should have some common error and error handler
throw new Error ( ` [clipboard] unknown excmd: ${ excmd } ` )
2017-10-19 20:15:01 +01:00
}
2017-10-28 19:20:31 +08:00
hidecmdline ( )
2017-10-19 20:15:01 +01:00
}
2017-10-12 04:02:01 +01:00
// {{{ Buffer/completion stuff
// TODO: Move autocompletions out of excmds.
2017-11-03 19:10:12 +00:00
/** @hidden */
2017-10-12 04:02:01 +01:00
//#background_helper
const DEFAULT_FAVICON = browser . extension . getURL ( "static/defaultFavicon.svg" )
2017-11-19 08:26:01 +00:00
/** Soon to be deprecated way of showing buffer completions */
2017-10-12 04:02:01 +01:00
//#background
export async function openbuffer() {
fillcmdline ( "buffer" )
2017-11-19 08:26:01 +00:00
messageActiveTab ( "commandline_frame" , "changecompletions" , [ await l ( listTabs ( ) ) ] )
showcmdline ( )
2017-10-12 04:02:01 +01:00
}
/** Change active tab */
//#background
export async function buffer ( n? : number | string ) {
if ( ! n || Number ( n ) == 0 ) return // Vimperator index starts at 1
if ( n === "#" ) {
n =
( await browser . tabs . query ( { currentWindow : true } ) ) . sort ( ( a , b ) = > {
return a . lastAccessed < b . lastAccessed ? 1 : - 1
} ) [ 1 ] . index + 1
}
2017-11-07 12:02:24 +00:00
if ( Number . isInteger ( Number ( n ) ) ) {
tabSetActive (
( await browser . tabs . query ( {
currentWindow : true ,
index : Number ( n ) - 1 ,
} ) ) [ 0 ] . id
)
// hacky search by url
} else {
let currtabs = await browser . tabs . query ( { currentWindow : true } )
// todo: choose best match
tabSetActive ( currtabs . filter ( ( t ) = > ( t [ "url" ] . includes ( String ( n ) ) || t [ "title" ] . toLowerCase ( ) . includes ( String ( n ) . toLowerCase ( ) ) ) ) [ 0 ] . id )
}
2017-10-12 04:02:01 +01:00
}
/** List of tabs in window and the last active tab. */
2017-11-03 19:10:12 +00:00
/** @hidden */
2017-10-12 04:02:01 +01:00
//#background_helper
async function getTabs() {
const tabs = await browser . tabs . query ( { currentWindow : true } )
const lastActive = tabs . sort ( ( a , b ) = > {
return a . lastAccessed < b . lastAccessed ? 1 : - 1
} ) [ 1 ]
tabs . sort ( ( a , b ) = > {
return a . index < b . index ? - 1 : 1
} )
console . log ( tabs )
return [ tabs , lastActive ]
}
/** innerHTML for a single Tab's representation in autocompletion */
2017-11-03 19:10:12 +00:00
/** @hidden */
2017-10-12 04:02:01 +01:00
//#background_helper
function formatTab ( tab : browser.tabs.Tab , prev? : boolean ) {
2017-11-15 00:41:53 +00:00
// This, like all this completion logic, needs to move.
const tabline = window . document . createElement ( 'div' )
tabline . className = "tabline"
const prefix = window . document . createElement ( 'span' )
if ( tab . active ) prefix . textContent += "%"
else if ( prev ) prefix . textContent += "#"
if ( tab . pinned ) prefix . textContent += "@"
prefix . textContent = prefix . textContent . padEnd ( 2 )
tabline . appendChild ( prefix )
2017-10-22 11:08:43 +01:00
// TODO: Dynamically set favicon dimensions. Should be able to use em.
2017-11-15 00:41:53 +00:00
const favicon = window . document . createElement ( 'img' )
favicon . src = tab . favIconUrl ? tab.favIconUrl : DEFAULT_FAVICON
tabline . appendChild ( favicon )
const titlespan = window . document . createElement ( 'span' )
titlespan . textContent = ` ${ tab . index + 1 } : ${ tab . title } `
tabline . appendChild ( titlespan )
const url = window . document . createElement ( 'a' )
url . className = 'url'
url . href = tab . url
url . text = tab . url
url . target = '_blank'
tabline . appendChild ( url )
console . log ( tabline )
return tabline . outerHTML
2017-10-12 04:02:01 +01:00
}
/** innerHTML for tab autocompletion div */
2017-11-03 19:10:12 +00:00
/** @hidden */
2017-10-12 04:02:01 +01:00
//#background_helper
async function listTabs() {
let buffers : string = "" ,
[ tabs , lastActive ] = await getTabs ( )
for ( let tab of tabs as Array < browser.tabs.Tab > ) {
buffers += tab === lastActive ? formatTab ( tab , true ) : formatTab ( tab )
}
return buffers
}
// }}}
// }}}
2017-11-05 14:10:11 +00:00
2017-11-09 00:41:07 +00:00
// {{{ SETTINGS
2017-11-19 06:05:15 +00:00
/ * * B i n d a s e q u e n c e o f k e y s t o a n e x c m d .
This is an easier - to - implement bodge while we work on vim - style maps .
Examples :
- ` bind G fillcmdline tabopen google `
- ` bind D composite tabclose | tabprev `
- ` bind j scrollline 20 `
- ` bind F hint -b `
Use [ [ composite ] ] if you want to execute multiple excmds . Use
[ [ fillcmdline ] ] to put a string in the cmdline and focus the cmdline
( otherwise the string is executed immediately ) .
See also :
- [ [ unbind ] ]
- [ [ reset ] ]
* /
2017-11-05 14:10:11 +00:00
//#background
2017-11-09 12:13:08 +00:00
export async function bind ( key : string , . . . bindarr : string [ ] ) {
let exstring = bindarr . join ( " " )
2017-11-05 14:10:11 +00:00
let nmaps = ( await browser . storage . sync . get ( "nmaps" ) ) [ "nmaps" ]
2017-11-19 06:05:15 +00:00
nmaps = ( nmaps == undefined ) ? Object . create ( null ) : nmaps
2017-11-05 14:10:11 +00:00
nmaps [ key ] = exstring
browser . storage . sync . set ( { nmaps } )
}
2017-11-19 06:05:15 +00:00
/ * * U n b i n d a s e q u e n c e o f k e y s s o t h a t t h e y d o n o t h i n g a t a l l .
See also :
- [ [ bind ] ]
- [ [ reset ] ]
* /
2017-11-05 14:10:11 +00:00
//#background
export async function unbind ( key : string ) {
2017-11-19 06:05:15 +00:00
bind ( key , "" )
2017-11-05 14:10:11 +00:00
}
2017-11-19 06:05:15 +00:00
/ * * R e s t o r e s a s e q u e n c e o f k e y s t o t h e i r d e f a u l t v a l u e .
See also :
- [ [ bind ] ]
- [ [ unbind ] ]
* /
2017-11-05 14:10:11 +00:00
//#background
export async function reset ( key : string ) {
let nmaps = ( await browser . storage . sync . get ( "nmaps" ) ) [ "nmaps" ]
nmaps = ( nmaps == undefined ) ? { } : nmaps
delete nmaps [ key ]
browser . storage . sync . set ( { nmaps } )
}
2017-11-09 00:41:07 +00:00
// }}}
// {{{ HINTMODE
//#background_helper
2017-11-18 01:51:46 +00:00
import * as hinting from './hinting_background'
2017-11-09 00:41:07 +00:00
2017-11-18 03:10:58 +00:00
/** Hint a page. Pass -b as first argument to open hinted page in background. */
2017-11-09 00:41:07 +00:00
//#background
2017-11-19 06:05:15 +00:00
export function hint ( option ? : "-b" ) {
2017-11-18 01:51:46 +00:00
if ( option === '-b' ) hinting . hintPageOpenInBackground ( )
else hinting . hintPageSimple ( )
2017-11-09 00:41:07 +00:00
}
2017-11-15 00:03:34 +00:00
2017-11-09 00:41:07 +00:00
// }}}
2017-11-05 14:10:11 +00:00
2017-10-21 12:54:15 +02:00
// vim: tabstop=4 shiftwidth=4 expandtab