Merge branch 'master' of github.com:cmcaine/tridactyl into orangenschalen-variable_hintname_length

This commit is contained in:
Oliver Blanthorn 2017-12-03 13:56:10 +00:00
commit 9dd2555984
No known key found for this signature in database
GPG key ID: 2BB8C36BB504BFF3
10 changed files with 294 additions and 39 deletions

26
doc/changelog.md Normal file
View file

@ -0,0 +1,26 @@
# Tridactyl changelogs
## Release 1.7.0
- History completion is massively improved: much faster, more relevant results, and less janky as you type.
- User configuration
- set [setting] without a value will inform you of the current value
- Add configuration options for hinting: `hintchars` and `hintorder`
- Add unset for resetting a bind to default
- You can now change default search engine with e.g, `set searchengine bing` (#60)
- The default new tab page can be replaced with any URL via `set newtab [url]` (#59)
- Add `gh` and `gH` and "homepages" setting (#96)
- Shift-tab and tab now will cycle around completions correctly
- `ys` now works on some older pages
- Add bmarks command for searching through bookmarks (#167)
- Add `hint -c [selector]`: add hints that match CSS selector
- Add text-to-speech hint mode on `;r`
- Allow `;p` to yank any element which contains text
- Add `;#` hint yank anchor mode
- Improve hint CSS by adding a border and making background semi-transparent
- Add `tabonly` command
- Fix hinting mysteriously not working on some pages (#168)
- Fix issue where command line would invisibly cover up part of the screen (#170)
- Bookmarks can now have spaces in their titles
- Fix some hints on sites such as pcgamer.co.uk
- Long page titles will no longer appear after URLs in completions

View file

@ -6,7 +6,7 @@ Replace Firefox's default control mechanism with one modelled on the one true ed
## Installing
[Get our "beta" builds!][amo-betas] These are updated on AMO with each commit to master on this repo; your browser will automatically update from there once a day. If you want more frequent updates, you can change `extensions.update.interval` in `about:config` to whatever time you want, say, 15 minutes (900 seconds).
[Get our "beta" builds!][amo-betas] These are updated on AMO with each commit to master on this repo; your browser will automatically update from there once a day. If you want more frequent updates, you can change `extensions.update.interval` in `about:config` to whatever time you want, say, 15 minutes (900 seconds). Changelogs for the stable versions on the AMO can be found [here](https://github.com/cmcaine/tridactyl/blob/master/doc/changelog.md).
Type `:help` for online help once you're in :)
@ -76,7 +76,7 @@ A pre-commit hook is added by `npm install` that simply runs `npm test`. If you
Ask in `#tridactyl` on [matrix.org][matrix-link], freenode, or [gitter][gitter-link]. We're friendly!
Default keybindings are currently best discovered by reading the source for the [normal mode parser](./src/parsers/normalmode.ts).
Default keybindings are currently best discovered by reading the [default config](./src/config.ts).
Development notes are in the doc directory, but they're mostly out of date now. Code is quite short and not *too* badly commented, though.

View file

@ -19,6 +19,7 @@ import * as excmds from './excmds_background'
import * as commandline_background from './commandline_background'
import * as controller from './controller'
import * as convert from './convert'
import * as config from './config'
import * as dom from './dom'
import * as hinting_background from './hinting_background'
import * as gobble_mode from './parsers/gobblemode'
@ -34,6 +35,7 @@ import * as webext from './lib/webext'
commandline_background,
controller,
convert,
config,
dom,
hinting_background,
gobble_mode,

View file

@ -40,6 +40,7 @@ function enableCompletions() {
activeCompletions = [
new Completions.BufferCompletionSource(completionsDiv),
new Completions.HistoryCompletionSource(completionsDiv),
new Completions.BmarkCompletionSource(completionsDiv),
]
const fragment = document.createDocumentFragment()
@ -197,21 +198,22 @@ function history(n){
/* Send the commandline to the background script and await response. */
function process() {
console.log(clInput.value)
clInput.value = getCompletion() || clInput.value
console.log(clInput.value)
sendExstr(clInput.value)
const command = getCompletion() || clInput.value
console.log(command)
hide_and_clear()
// Save non-secret commandlines to the history.
const [func,...args] = clInput.value.trim().split(/\s+/)
const [func,...args] = command.trim().split(/\s+/)
if (! browser.extension.inIncognitoContext &&
! (func === 'winopen' && args[0] === '-private')
) {
state.cmdHistory = state.cmdHistory.concat([clInput.value])
state.cmdHistory = state.cmdHistory.concat([command])
}
console.log(state.cmdHistory)
cmdline_history_position = 0
hide_and_clear()
sendExstr(command)
}
export function fillcmdline(newcommand?: string, trailspace = true){

View file

@ -301,8 +301,10 @@ abstract class CompletionSourceFuse extends CompletionSource {
if (this.state != "hidden"){
let visopts = this.options.filter((o) => o.state != "hidden")
let currind = visopts.findIndex((o) => o.state == "focused")
if ((inc < 0) && (currind == -1)) inc += 1
this.deselect()
this.select(visopts[currind + inc])
this.select(visopts[(currind + inc + visopts.length) % visopts.length
])
return true
} else return false
}
@ -338,11 +340,109 @@ class HistoryCompletionOption extends CompletionOptionHTML implements Completion
}
}
class BmarkCompletionOption extends CompletionOptionHTML implements CompletionOptionFuse {
public fuseKeys = []
constructor(public value: string, bmark: browser.bookmarks.BookmarkTreeNode) {
super()
if (! bmark.title) {
bmark.title = new URL(bmark.url).host
}
// Push properties we want to fuzmatch on
this.fuseKeys.push(bmark.title, bmark.url)
// Create HTMLElement
// need to download favicon
const favIconUrl = DEFAULT_FAVICON
// const favIconUrl = tab.favIconUrl ? tab.favIconUrl : DEFAULT_FAVICON
this.html = html`<tr class="HistoryCompletionOption option">
<td class="prefix">${"".padEnd(2)}</td>
<td></td>
<td>${bmark.title}</td>
<td><a class="url" target="_blank" href=${bmark.url}>${bmark.url}</a></td>
</tr>`
}
}
function sleep(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms))
}
export class BmarkCompletionSource extends CompletionSourceFuse {
public options: BmarkCompletionOption[]
constructor(private _parent) {
super(
[
"bmarks ",
],
"BmarkCompletionSource", "Bookmarks"
)
this._parent.appendChild(this.node)
}
public async filter(exstr: string) {
this.lastExstr = exstr
const [prefix, query] = this.splitOnPrefix(exstr)
// Hide self and stop if prefixes don't match
if (prefix) {
// Show self if prefix and currently hidden
if (this.state === 'hidden') {
this.state = 'normal'
}
} else {
this.state = 'hidden'
return
}
this.options = (await this.scoreOptions(query, 10)).map(
page => new BmarkCompletionOption(page.url, page)
)
this.updateChain()
}
updateChain() {
// Options are pre-trimmed to the right length.
this.options.forEach(option => option.state = 'normal')
// Call concrete class
this.updateDisplay()
}
onInput() {}
private async scoreOptions(query: string, n: number) {
// Search bookmarks, dedupe and sort by frecency
let bookmarks = await browserBg.bookmarks.search({query})
bookmarks = bookmarks.filter(b=>{
try {
return new URL(b.url)
} catch (e) {
return false;
}
})
bookmarks.sort((a, b) => b.dateAdded - a.dateAdded)
return bookmarks.slice(0, n)
}
select(option: CompletionOption) {
if (this.lastExstr !== undefined && option !== undefined) {
this.completion = "open " + option.value
option.state = 'focused'
this.lastFocused = option
} else {
throw new Error("lastExstr and option must be defined!")
}
}
}
export class HistoryCompletionSource extends CompletionSourceFuse {
public options: HistoryCompletionOption[]

View file

@ -80,6 +80,28 @@ const DEFAULTS = o({
"A": "bmark",
}),
"searchengine": "google",
"searchurls": o({
"google":"https://www.google.com/search?q=",
"scholar":"https://scholar.google.com/scholar?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/Special:Search/",
"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=",
"startpage":"https://startpage.com/do/search?language=english&cat=web&query=",
"github":"https://github.com/search?utf8=✓&q=",
"searx":"https://searx.me/?category_general=on&q=",
"cnrtl":"http://www.cnrtl.fr/lexicographie/",
"osm":"https://www.openstreetmap.org/search?query=",
"mdn":"https://developer.mozilla.org/en-US/search?q=",
"gentoo_wiki":"https://wiki.gentoo.org/index.php?title=Special%3ASearch&profile=default&fulltext=Search&search=",
"qwant":"https://www.qwant.com/?q=",
}),
"newtab": undefined,
"storageloc": "sync",
"homepages": [],

View file

@ -14,6 +14,7 @@ console.log("Tridactyl content script loaded, boss!")
// Add various useful modules to the window for debugging
import * as commandline_content from './commandline_content'
import * as convert from './convert'
import * as config from './config'
import * as dom from './dom'
import * as excmds from './excmds_content'
import * as hinting_content from './hinting'
@ -28,6 +29,7 @@ import * as webext from './lib/webext'
browserBg: webext.browserBg,
commandline_content,
convert,
config,
dom,
excmds,
hinting_content,

View file

@ -75,26 +75,6 @@ import * as config from './config'
//#background_helper
export const cmd_params = new Map<string, Map<string, string>>()
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/Special:Search/"],
["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="],
["startpage","https://www.startpage.com/do/search?query="],
["github","https://github.com/search?utf8=✓&q="],
["searx","https://searx.me/?category_general=on&q="],
["cnrtl","http://www.cnrtl.fr/lexicographie/"],
["osm","https://www.openstreetmap.org/search?query="],
["mdn","https://developer.mozilla.org/en-US/search?q="],
["gentoo_wiki","https://wiki.gentoo.org/index.php?title=Special%3ASearch&profile=default&fulltext=Search&search="],
])
// map a page-relation (next or previous) to a fallback pattern to match link texts against
const REL_PATTERN = {
next: /^(?:next|newer)\b|»|>>/i,
@ -109,8 +89,9 @@ function hasScheme(uri: string) {
/** @hidden */
function searchURL(provider: string, query: string) {
if (provider == "search") provider = config.get("searchengine")
if (SEARCH_URLS.has(provider)) {
const url = new URL(SEARCH_URLS.get(provider) + encodeURIComponent(query))
let searchurlprovider = config.get("searchurls", provider)
if (searchurlprovider !== undefined){
const url = new URL(searchurlprovider + encodeURIComponent(query))
// URL constructor doesn't convert +s because they're valid literals in
// the standard it adheres to. But they are special characters in
// x-www-form-urlencoded and e.g. google excepts query parameters in
@ -258,6 +239,7 @@ export async function reloadhard(n = 1) {
//#content
export function open(...urlarr: string[]) {
let url = urlarr.join(" ")
console.log("open url:" + url)
window.location.href = forceURI(url)
}
@ -274,7 +256,7 @@ export function home(all: "false" | "true" = "false"){
let homepages = config.get("homepages")
console.log(homepages)
if (homepages.length > 0){
if (all === "false") open(homepages[-1])
if (all === "false") open(homepages[homepages.length - 1])
else {
homepages.map(t=>tabopen(t))
}
@ -394,9 +376,8 @@ export function urlparent (){
@hidden
*/
//#content
export function geturlsforlinks(rel: string){
let elems = document.querySelectorAll("link[rel='" + rel + "']") as NodeListOf<HTMLLinkElement>
console.log(rel, elems)
export function geturlsforlinks(reltype = "rel", rel: string){
let elems = document.querySelectorAll("link[" + reltype + "='" + rel + "']") as NodeListOf<HTMLLinkElement>
if (elems)
return Array.prototype.map.call(elems, x => x.href)
return []
@ -896,13 +877,16 @@ export async function clipboard(excmd: "open"|"yank"|"yankshort"|"yankcanon"|"ta
let urls = []
switch (excmd) {
case 'yankshort':
urls = await geturlsforlinks("shortlink")
urls = await geturlsforlinks("rel", "shortlink")
if (urls.length == 0) {
urls = await geturlsforlinks("rev", "canonical")
}
if (urls.length > 0) {
messageActiveTab("commandline_frame", "setClipboard", [urls[0]])
break
}
case 'yankcanon':
urls = await geturlsforlinks("canonical")
urls = await geturlsforlinks("rel", "canonical")
if (urls.length > 0) {
messageActiveTab("commandline_frame", "setClipboard", [urls[0]])
break
@ -1002,6 +986,12 @@ export function bind(key: string, ...bindarr: string[]){
config.set("nmaps",exstring,key)
}
/** Set a search engine keyword for use with *open or `set searchengine` */
//#background
export function searchsetkeyword(keyword: string, url: string){
config.set("searchurls",forceURI(url),keyword)
}
/** Unbind a sequence of keys so that they do nothing at all.
See also:
@ -1032,6 +1022,103 @@ export async function reset(key: string){
browser.storage.sync.set({nmaps})
}
/** Deletes various privacy-related items.
The list of possible arguments can be found here:
https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/browsingData/DataTypeSet
Additional, tridactyl-specific arguments are:
- commandline: Removes the in-memory commandline history.
- tridactyllocal: Removes all tridactyl storage local to this machine. Use it with
commandline if you want to delete your commandline history.
- tridactylsync: Removes all tridactyl storage associated with your Firefox Account (i.e, all user configuration, by default).
These arguments aren't affected by the timespan parameter.
Timespan parameter:
-t [0-9]+(m|h|d|w)
Examples:
`sanitize all` -> Deletes everything
`sanitize history` -> Deletes all history
`sanitize commandline tridactyllocal tridactylsync` -> Deletes every bit of data Tridactyl holds
`sanitize cookies -t 3d` -> Deletes cookies that were set during the last three days.
*/
//#background
export async function sanitize(...args: string[]) {
let flagpos = args.indexOf("-t")
let since = {}
// If the -t flag has been given and there is an arg after it
if (flagpos > -1) {
if (flagpos < args.length - 1) {
let match = args[flagpos + 1].match('^([0-9])+(m|h|d|w)$')
// If the arg of the flag matches Pentadactyl's sanitizetimespan format
if (match !== null && match.length == 3) {
// Compute the timespan in milliseconds and get a Date object
let millis = parseInt(match[1]) * 1000
switch (match[2]) {
case 'w': millis *= 7
case 'd': millis *= 24
case 'h': millis *= 60
case 'm': millis *= 60
}
since = { "since": (new Date()).getTime() - millis }
} else {
console.log(":sanitize error: expected time format: ^([0-9])+(m|h|d|w)$, given format:" + args[flagpos+1])
return
}
} else {
console.log(":sanitize error: -t given but no following arguments")
return
}
}
let dts = {
"cache": false,
"cookies": false,
"downloads": false,
"formData": false,
"history": false,
"localStorage": false,
"passwords": false,
"serviceWorkers": false,
// These are Tridactyl-specific
"commandline": false,
"tridactyllocal": false,
"tridactylsync": false,
/* When this one is activated, a lot of errors seem to pop up in
the console. Keeping it disabled is probably a good idea.
"pluginData": false,
*/
/* These 3 are supported by Chrome and Opera but not by Firefox yet.
"fileSystems": false,
"indexedDB": false,
"serverBoundCertificates": false,
*/
}
if (args.find(x => x == "all") !== undefined) {
for (let attr in dts)
dts[attr] = true
} else {
// We bother checking if dts[x] is false because
// browser.browsingData.remove() is very strict on the format of the
// object it expects
args.map(x => { if (dts[x] === false) dts[x] = true })
}
// Tridactyl-specific items
if (dts.commandline === true)
state.cmdHistory = []
delete dts.commandline
if (dts.tridactyllocal === true)
browser.storage.local.clear()
delete dts.tridactyllocal
if (dts.tridactylsync === true)
browser.storage.sync.clear()
delete dts.tridactylsync
// Global items
browser.browsingData.remove(since, dts)
}
/** Bind a quickmark for the current URL to a key.
Afterwards use go[key], gn[key], or gw[key] to [[open]], [[tabopen]], or

View file

@ -1,7 +1,7 @@
{
"manifest_version": 2,
"name": "Tridactyl",
"version": "1.6.1",
"version": "1.7.0",
"icons": {
"64": "static/logo/Tridactyl_64px.png",
"100": "static/logo/Tridactyl_100px.png",
@ -38,6 +38,7 @@
"permissions": [
"activeTab",
"bookmarks",
"browsingData",
"contextMenus",
"clipboardWrite",
"clipboardRead",
@ -57,4 +58,4 @@
"strict_min_version": "54.0"
}
}
}
}

View file

@ -42,6 +42,19 @@ input {
border-spacing: 0;
table-layout: fixed;
}
/* redundancy 2: redundancy 2: more redundancy */
#completions .BmarkCompletionSource {
max-height: calc(20 * var(--option-height));
min-height: calc(10 * var(--option-height));
}
#completions .BmarkCompletionSource table {
width: 100%;
font-size: 9pt;
border-spacing: 0;
table-layout: fixed;
}
/* redundancy ends */
#completions .BufferCompletionSource {