mirror of
https://github.com/vale981/tridactyl
synced 2025-03-06 10:01:39 -05:00
remote/origin conflict resolved
This commit is contained in:
commit
6b8922670d
24 changed files with 2481 additions and 2375 deletions
47
.tridactylrc
Normal file
47
.tridactylrc
Normal file
|
@ -0,0 +1,47 @@
|
|||
" bovine3dom's dogfood
|
||||
|
||||
" Move this to $XDG_CONFIG_DIR/tridactyl/tridactylrc (that's
|
||||
" ~/.config/tridactyl/tridactylrc to mere mortals) or ~/.tridactylrc and
|
||||
" install the native messenger (:installnative in Tridactyl). Run :source to
|
||||
" get it in the browser, or just restart.
|
||||
|
||||
" NB: If you want "vim-like" behaviour where removing a line from
|
||||
" here makes the setting disappear, uncomment the line below.
|
||||
|
||||
"sanitise tridactyllocal tridactylsync
|
||||
|
||||
"
|
||||
" Binds
|
||||
"
|
||||
|
||||
" Comment toggler for Reddit and Hacker News
|
||||
bind ;c hint -c [class*="expand"],[class="togg"]
|
||||
|
||||
"
|
||||
" Misc settings
|
||||
"
|
||||
|
||||
set editorcmd st vim
|
||||
|
||||
" Sane hinting mode
|
||||
set hintfiltermode vimperator-reflow
|
||||
set hintchars 4327895610
|
||||
|
||||
" Make Tridactyl work on more sites at the expense of some security
|
||||
set csp clobber
|
||||
|
||||
" Make quickmarks for the sane Tridactyl issue view
|
||||
quickmark t https://github.com/cmcaine/tridactyl/issues?utf8=%E2%9C%93&q=sort%3Aupdated-desc+
|
||||
|
||||
"
|
||||
" URL redirects
|
||||
"
|
||||
|
||||
" New reddit is bad
|
||||
autocmd DocStart www.reddit.com urlmodify -t www old
|
||||
" Mosquito nets won't make themselves
|
||||
autocmd DocStart www.amazon.co.uk urlmodify -t www smile
|
||||
|
||||
|
||||
" This will have to do until someone writes us a nice syntax file :)
|
||||
" vim: set filetype=vim:
|
67
CHANGELOG.md
67
CHANGELOG.md
|
@ -1,12 +1,77 @@
|
|||
# Tridactyl changelog
|
||||
|
||||
## Release 1.11.0 / Unreleased
|
||||
## Release 1.12.0 / 2018-05-13
|
||||
|
||||
- Add container support
|
||||
- `hint` will now open links in the current container
|
||||
- there is a new setting, `set tabopencontaineraware [false|true]`, which will make `tabopen` open new tabs in the current container
|
||||
- Add extra `<CA-Esc>` bind to toggle ignore mode by popular demand
|
||||
- Fix errors related to missing native messenger on Firefox launch
|
||||
|
||||
## Release 1.11.2 / 2018-05-11
|
||||
|
||||
- Hotfix to prevent "config undefined" errors on browser start if no rc file was found
|
||||
- It was mysteriously only reproducible sometimes...
|
||||
- Make newtab changelog a bit wider
|
||||
|
||||
## Release 1.11.1 / 2018-05-11
|
||||
|
||||
- **Add "tridactylrc" support**
|
||||
- Stick a bunch of commands you want to run at startup in one of:
|
||||
- `$XDG_CONFIG_DIR/tridactyl/tridactylrc`
|
||||
- `~/.config/tridactyl/tridactylrc`
|
||||
- `~/.tridactylrc`
|
||||
- [Example file available here](https://github.com/cmcaine/tridactyl/blob/master/.tridactylrc)
|
||||
- You can run any file you want with `source [absolute path to file]`. Bonus points if you can think of something sensible to do with `source` in an `autocmd`.
|
||||
- If you want vim-style configuration where nothing persists except that which is in the rc file, simply add `sanitise tridactyllocal tridactylsync` to the top of your rc file.
|
||||
- Only whole-line comments are supported at the moment, in the VimL style where lines start with a quote mark: "
|
||||
|
||||
- Native messenger updated to 0.1.3
|
||||
- Add rc file reader
|
||||
- Add ability to read environment variables
|
||||
- Make read understand ~ and environment variables (used in `source`)
|
||||
|
||||
- Readme updated
|
||||
- Add statistics page and `guiset`
|
||||
|
||||
- Bug fixes
|
||||
- `guiset` can now cope with multiple Firefox instances running simultaneously provided they are started with profiles explicitly via the command line.
|
||||
|
||||
- Deprecations
|
||||
- Remove buffers,tabs as promised
|
||||
- Inform people pressing `I` of the new bind
|
||||
|
||||
## Release 1.11.0 / 2018-05-09
|
||||
|
||||
- You can now edit the Firefox GUI from Tridactyl with `guiset`. You must restart Firefox after using `guiset` to see the effects.
|
||||
- e.g, `guiset gui none` or `guiset gui full`.
|
||||
- see all the options with `help guiset` and following the links.
|
||||
- **Only minimally tested. Back up your precious userChrome.css if you care about it!**
|
||||
|
||||
- You can now choose to bypass [CSP](https://en.wikipedia.org/wiki/Content_Security_Policy) on all sites with `set csp clobber`. If you change your mind, just `unset csp`, and restart your browser.
|
||||
- This, for example, allows Tridactyl to run on pages such as https://raw.githubusercontent.com/cmcaine/tridactyl/master/CHANGELOG.md, but it could also allow other scripts to run on pages, making the Internet as dangerous as it was about 2 or 3 years ago before CSP was introduced.
|
||||
- Once this [bug](https://bugzilla.mozilla.org/show_bug.cgi?id=1267027) in Firefox is fixed, you won't have to clobber CSP.
|
||||
|
||||
- Tridactyl will no longer update while the browser is running in an attempt to fix issues where the add-on would be unresponsive after an update; instead, it will only update on browser launch.
|
||||
- This includes manual updates via `about:addons`. You'll need to restart the browser after clicking "Check for updates".
|
||||
|
||||
- `set newtab news.bbc.co.uk` etc. now looks much less janky
|
||||
|
||||
- Minor new features
|
||||
- Add !s alias for silent exclaim
|
||||
- `termite` and `terminator` support with `set editorcmd auto`
|
||||
- Allow binding <Esc> (not recommended...)
|
||||
- AMO explains why we need each new permission
|
||||
- Native messenger documentation improved, making it clear that we haven't reimplemented IRC in the browser.
|
||||
|
||||
- Minor bug fixes
|
||||
- Remove pixel gap under command bar (#442)
|
||||
- Native installer no longer requires pip and supports Debian's `which`
|
||||
- Help page links are more legible on rubbish screens
|
||||
- Turn 'q' and 'qall' into aliases
|
||||
- Fix typo regarding binding of special keys on help page
|
||||
- `focusinput` is now better at finding elements to focus
|
||||
|
||||
## Release 1.10.1 / 2018-05-04
|
||||
|
||||
- Add tabcloseallto{right,left} bound to `gx0` and `gx$`
|
||||
|
|
|
@ -2,6 +2,18 @@
|
|||
|
||||
set -e
|
||||
|
||||
echoerr() {
|
||||
red="\033[31m"
|
||||
normal="\e[0m"
|
||||
echo -e "$red$@$normal" >&2
|
||||
}
|
||||
|
||||
sedEscape() {
|
||||
sed 's/[&/\]/\\&/g' <<< "$@"
|
||||
}
|
||||
|
||||
trap "echoerr 'Failed to install!'" ERR
|
||||
|
||||
# To install, curl -fsSl 'url to this script' | bash
|
||||
|
||||
XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config/tridactyl}"
|
||||
|
@ -35,21 +47,17 @@ else
|
|||
curl -sS --create-dirs -o "$native_file" "$native_loc"
|
||||
fi
|
||||
|
||||
native_file_escaped=$(sed 's/[&/\]/\\&/g' <<< "$native_file_final")
|
||||
|
||||
sed -i.bak "s/REPLACE_ME_WITH_SED/$native_file_escaped/" "$manifest_file"
|
||||
sed -i.bak "s/REPLACE_ME_WITH_SED/$(sedEscape "$native_file_final")/" "$manifest_file"
|
||||
chmod +x $native_file
|
||||
|
||||
# Requirements for native messenger
|
||||
python_path=$(which python3)
|
||||
pip_path=$(which pip3)
|
||||
python_file_escaped=$(sed 's/[&/\]/\\&/g' <<< "$python_path")
|
||||
if [[ -x "$python_path" ]] && [[ -x "$pip_path" ]]; then
|
||||
sed -i.bak "1s/.*/#!$python_file_escaped/" "$native_file"
|
||||
python_path=$(which python3) || python_path=""
|
||||
if [[ -x "$python_path" ]]; then
|
||||
sed -i.bak "1s/.*/#!$(sedEscape "$python_path")/" "$native_file"
|
||||
mv "$native_file" "$native_file_final"
|
||||
else
|
||||
echo "Error: Python 3 and pip3 must exist in PATH."
|
||||
echo "Please install them and run this script again."
|
||||
echoerr "Error: Python 3 must exist in PATH."
|
||||
echoerr "Please install it and run this script again."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
|
@ -8,8 +8,7 @@ import struct
|
|||
import subprocess
|
||||
import tempfile
|
||||
|
||||
VERSION = "0.1.1"
|
||||
|
||||
VERSION = "0.1.3"
|
||||
|
||||
class NoConnectionError(Exception):
|
||||
""" Exception thrown when stdin cannot be read """
|
||||
|
@ -22,11 +21,10 @@ def eprint(*args, **kwargs):
|
|||
print(*args, file=sys.stderr, flush=True, **kwargs)
|
||||
|
||||
|
||||
def _getenv(variable, default):
|
||||
def getenv(variable, default):
|
||||
""" Get an environment variable value, or use the default provided """
|
||||
return os.environ.get(variable) or default
|
||||
|
||||
|
||||
def getMessage():
|
||||
"""Read a message from stdin and decode it.
|
||||
|
||||
|
@ -66,6 +64,43 @@ def sendMessage(encodedMessage):
|
|||
sys.stdout.buffer.flush()
|
||||
|
||||
|
||||
def findUserConfigFile():
|
||||
""" Find a user config file, if it exists. Return the file path, or None
|
||||
if not found
|
||||
"""
|
||||
home = os.path.expanduser('~')
|
||||
config_dir = getenv('XDG_CONFIG_HOME', os.path.expanduser('~/.config'))
|
||||
|
||||
# Will search for files in this order
|
||||
candidate_files = [
|
||||
os.path.join(config_dir, "tridactyl", "tridactylrc"),
|
||||
os.path.join(home, '.tridactylrc')
|
||||
]
|
||||
|
||||
config_path = None
|
||||
|
||||
# find the first path in the list that exists
|
||||
for path in candidate_files:
|
||||
if os.path.isfile(path):
|
||||
config_path = path
|
||||
break
|
||||
|
||||
return config_path
|
||||
|
||||
|
||||
def getUserConfig():
|
||||
# look it up freshly each time - the user could have moved or killed it
|
||||
cfg_file = findUserConfigFile()
|
||||
|
||||
# no file, return
|
||||
if not cfg_file:
|
||||
return None
|
||||
|
||||
# for now, this is a simple file read, but if the files can
|
||||
# include other files, that will need more work
|
||||
return open(cfg_file, 'r').read()
|
||||
|
||||
|
||||
def handleMessage(message):
|
||||
""" Generate reply from incoming message. """
|
||||
cmd = message["cmd"]
|
||||
|
@ -74,6 +109,13 @@ def handleMessage(message):
|
|||
if cmd == 'version':
|
||||
reply = {'version': VERSION}
|
||||
|
||||
elif cmd == 'getconfig':
|
||||
file_content = getUserConfig()
|
||||
if file_content:
|
||||
reply['content'] = file_content
|
||||
else:
|
||||
reply['code'] = 'File not found'
|
||||
|
||||
elif cmd == 'run':
|
||||
commands = message["command"]
|
||||
|
||||
|
@ -92,7 +134,7 @@ def handleMessage(message):
|
|||
|
||||
elif cmd == 'read':
|
||||
try:
|
||||
with open(message["file"], "r") as file:
|
||||
with open(os.path.expandvars(os.path.expanduser(message["file"])), "r") as file:
|
||||
reply['content'] = file.read()
|
||||
reply['code'] = 0
|
||||
except FileNotFoundError:
|
||||
|
@ -116,6 +158,9 @@ def handleMessage(message):
|
|||
file.write(message["content"])
|
||||
reply['content'] = filepath
|
||||
|
||||
elif cmd == 'env':
|
||||
reply['content'] = getenv(message["var"], "")
|
||||
|
||||
else:
|
||||
reply = {'cmd': 'error', 'error': 'Unhandled message'}
|
||||
eprint('Unhandled message: {}'.format(message))
|
||||
|
|
4134
package-lock.json
generated
4134
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -34,7 +34,7 @@
|
|||
},
|
||||
"scripts": {
|
||||
"build": "scripts/build.sh",
|
||||
"watch": "chokidar src scripts --initial --silent -i 'src/excmds_{background,content}.ts' -i 'src/static/docs' -c 'npm run build'",
|
||||
"watch": "echo 'watch is broken, use build instead'; exit 0; chokidar src scripts --initial --silent -i 'src/excmds_{background,content}.ts' -i 'src/static/docs' -c 'npm run build'",
|
||||
"clean": "rm -rf build generated",
|
||||
"test": "npm run build && jest --silent",
|
||||
"update-buildsystem": "rm -rf src/node_modules; npm run clean"
|
||||
|
|
|
@ -117,7 +117,7 @@ See `:help bind` for details about this command.
|
|||
|
||||
- Navigation to any about:\* pages using `:open` requires the native messenger.
|
||||
- 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. We've developed [quite a good one](src/static/userChrome-minimal.css) that makes windowed Firefox behave more like full-screen mode, but it's well commented, so you can make your own.
|
||||
- Tridactyl now supports changing the Firefox GUI if you have the native messenger installed via `guiset`. There's quite a few options available, but `guiset gui none` is probably what you want, perhaps followed up with `guiset tabs always`.
|
||||
|
||||
## Frequently asked questions
|
||||
|
||||
|
@ -195,6 +195,9 @@ See `:help bind` for details about this command.
|
|||
|
||||
Press `j` and see if you scroll down :) There's no status line yet: see [#210](https://github.com/cmcaine/tridactyl/issues/210).
|
||||
|
||||
- Does anyone actually use Tridactyl?
|
||||
|
||||
In addition to the developers, some other people do. Mozilla keeps tabs on them [here](https://addons.mozilla.org/en-US/firefox/addon/tridactyl-vim/statistics/?last=30).
|
||||
|
||||
|
||||
## Contributing
|
||||
|
|
|
@ -27,6 +27,7 @@ import * as gobble_mode from "./parsers/gobblemode"
|
|||
import * as input_mode from "./parsers/inputmode"
|
||||
import * as itertools from "./itertools"
|
||||
import * as keyseq from "./keyseq"
|
||||
import * as request from "./requests"
|
||||
import * as native from "./native_background"
|
||||
import * as msgsafe from "./msgsafe"
|
||||
import state from "./state"
|
||||
|
@ -47,8 +48,37 @@ import * as webext from "./lib/webext"
|
|||
keydown_background,
|
||||
native,
|
||||
keyseq,
|
||||
request,
|
||||
msgsafe,
|
||||
state,
|
||||
webext,
|
||||
l: prom => prom.then(console.log).catch(console.error),
|
||||
})
|
||||
|
||||
// This should be removed once https://bugzilla.mozilla.org/show_bug.cgi?id=1267027 is fixed
|
||||
let cspListener
|
||||
if (config.get("csp") == "clobber") {
|
||||
cspListener = browser.webRequest.onHeadersReceived.addListener(
|
||||
request.addurltocsp,
|
||||
{ urls: ["<all_urls>"], types: ["main_frame"] },
|
||||
["blocking", "responseHeaders"],
|
||||
)
|
||||
}
|
||||
browser.storage.onChanged.addListener((changes, areaname) => {
|
||||
if (config.get("csp") == "clobber") {
|
||||
cspListener = browser.webRequest.onHeadersReceived.addListener(
|
||||
request.addurltocsp,
|
||||
{ urls: ["<all_urls>"], types: ["main_frame"] },
|
||||
["blocking", "responseHeaders"],
|
||||
)
|
||||
} else {
|
||||
// This doesn't work. :(
|
||||
// browser.webRequest.onHeadersReceived.removeListener(cspListener)
|
||||
}
|
||||
})
|
||||
|
||||
// Prevent Tridactyl from being updated while it is running in the hope of fixing #290
|
||||
browser.runtime.onUpdateAvailable.addListener(_ => {})
|
||||
|
||||
// Try to load an RC file
|
||||
excmds.source_quiet()
|
||||
|
|
|
@ -123,6 +123,8 @@ const DEFAULTS = o({
|
|||
";#": "hint -#",
|
||||
";v": "hint -W exclaim_quiet mpv",
|
||||
"<S-Insert>": "mode ignore",
|
||||
"<CA-Esc>": "mode ignore",
|
||||
I: "fillcmdline Ignore mode is now toggled by pressing <S-Insert>",
|
||||
a: "current_url bmark",
|
||||
A: "bmark",
|
||||
zi: "zoom 0.1 true",
|
||||
|
@ -160,6 +162,8 @@ const DEFAULTS = o({
|
|||
tlast: "tablast",
|
||||
bd: "tabclose",
|
||||
bdelete: "tabclose",
|
||||
quit: "tabclose",
|
||||
q: "tabclose",
|
||||
sanitize: "sanitise",
|
||||
tutorial: "tutor",
|
||||
h: "help",
|
||||
|
@ -252,10 +256,18 @@ const DEFAULTS = o({
|
|||
"curl -fsSl https://raw.githubusercontent.com/cmcaine/tridactyl/master/native/install.sh | bash",
|
||||
profiledir: "auto",
|
||||
|
||||
// Container settings
|
||||
// If enabled, tabopen opens a new tab in the currently active tab's container.
|
||||
tabopencontaineraware: "false",
|
||||
|
||||
// Performance related settings
|
||||
|
||||
// number of most recent results to ask Firefox for. We display the top 20 or so most frequently visited ones.
|
||||
historyresults: "50",
|
||||
|
||||
// Security settings
|
||||
|
||||
csp: "untouched", // change this to "clobber" to ruin the CSP of all sites and make Tridactyl run a bit better on some of them, e.g. raw.github*
|
||||
})
|
||||
|
||||
/** Given an object and a target, extract the target if it exists, else return undefined
|
||||
|
|
29
src/config_rc.ts
Normal file
29
src/config_rc.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
import * as Controller from "./controller"
|
||||
import * as Native from "./native_background"
|
||||
import Logger from "./logging"
|
||||
const logger = new Logger("rc")
|
||||
|
||||
export async function source(filename = "auto") {
|
||||
let rctext = ""
|
||||
if (filename == "auto") {
|
||||
rctext = await Native.getrc()
|
||||
} else {
|
||||
rctext = (await Native.read(filename)).content
|
||||
}
|
||||
if (rctext === undefined) return false
|
||||
runRc(rctext)
|
||||
return true
|
||||
}
|
||||
|
||||
export async function runRc(rc: string) {
|
||||
for (let cmd of rcFileToExCmds(rc)) {
|
||||
await Controller.acceptExCmd(cmd)
|
||||
}
|
||||
}
|
||||
|
||||
export function rcFileToExCmds(rcText: string): string[] {
|
||||
const excmds = rcText.split("\n")
|
||||
|
||||
// Remove comment lines
|
||||
return excmds.filter(x => x != "" && !x.trim().startsWith('"'))
|
||||
}
|
|
@ -83,7 +83,7 @@ function* ParserController() {
|
|||
acceptExCmd(exstr)
|
||||
} catch (e) {
|
||||
// Rumsfeldian errors are caught here
|
||||
logger.error("Tridactyl ParserController fatally wounded:", e)
|
||||
logger.error("An error occurred in the controller: ", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,21 +6,27 @@ import * as CSS from "css"
|
|||
// type: "rule", selectors: [string], declarations: [
|
||||
// {type: "declaration", property: string, value: string}
|
||||
|
||||
/** Find rules in sheet that match selector */
|
||||
export function findCssRules(
|
||||
ruleToFind: string,
|
||||
selector: string,
|
||||
sheet: CSS.Stylesheet,
|
||||
): number[] {
|
||||
const filtSheet = [...sheet.stylesheet.rules.entries()].filter(x => {
|
||||
const rule = x[1]
|
||||
return (
|
||||
rule.type == "rule" &&
|
||||
rule["selectors"].filter(sel => sel == ruleToFind).length > 0
|
||||
)
|
||||
return rule.type == "rule" && rule["selectors"].indexOf(selector) > -1
|
||||
})
|
||||
return filtSheet.map(x => x[0])
|
||||
}
|
||||
|
||||
// TODO: make this more flexible with cleverer matching of selectors, merging of options
|
||||
/** Rulename -> { name: <selector>, options: { <option-name>: <css-string> } }
|
||||
*
|
||||
* Multi-level map of rulename, options available for rule and css for each option.
|
||||
*
|
||||
* *findCssRules and changeSingleCss rely on the selector not containing a comma.*
|
||||
*
|
||||
* TODO: make this more flexible with cleverer matching of selectors, merging of options
|
||||
*
|
||||
*/
|
||||
export const potentialRules = {
|
||||
hoverlink: {
|
||||
name: `statuspanel[type="overLink"]`,
|
||||
|
@ -28,8 +34,8 @@ export const potentialRules = {
|
|||
none: `display: none !important;`,
|
||||
right: `right: 0; display: inline;`,
|
||||
left: ``,
|
||||
"top-left": `top: 2em; display: inline;`,
|
||||
"top-right": `top: 2em; right: 0; display: inline;`,
|
||||
"top-left": `top: 2em; z-index: 2; display: inline;`,
|
||||
"top-right": `top: 2em; z-index: 2; right: 0; display: inline;`,
|
||||
},
|
||||
},
|
||||
tabstoolbar: {
|
||||
|
@ -107,6 +113,10 @@ export const potentialRules = {
|
|||
//
|
||||
// was just a simple show/hide if the characters appeared in the setting
|
||||
|
||||
/** Rules that index into potentialRules or metaRules
|
||||
*
|
||||
* Please don't add cycles to this table :)
|
||||
*/
|
||||
export const metaRules = {
|
||||
gui: {
|
||||
none: {
|
||||
|
@ -127,14 +137,17 @@ export const metaRules = {
|
|||
tabs: {
|
||||
none: {
|
||||
tabstoolbar: "none",
|
||||
navtoolboxunfocused: "hide",
|
||||
},
|
||||
always: {
|
||||
tabstoolbar: "show",
|
||||
tabstoolbarunfocused: "show",
|
||||
navtoolboxunfocused: "show",
|
||||
},
|
||||
autohide: {
|
||||
tabstoolbar: "show",
|
||||
tabstoolbarunfocused: "hide",
|
||||
navtoolboxunfocused: "hide",
|
||||
},
|
||||
},
|
||||
navbar: {
|
||||
|
@ -151,39 +164,40 @@ export const metaRules = {
|
|||
},
|
||||
}
|
||||
|
||||
/** Add desired non-meta rule to stylesheet replacing existing rule with the same selector if present */
|
||||
export function changeSingleCss(
|
||||
rulename: string,
|
||||
optionname: string,
|
||||
sheet: CSS.Stylesheet,
|
||||
): CSS.Stylesheet {
|
||||
const ruleInds = findCssRules(potentialRules[rulename]["name"], sheet)
|
||||
const desRule =
|
||||
potentialRules[rulename]["name"] +
|
||||
" {" +
|
||||
potentialRules[rulename]["options"][optionname] +
|
||||
"}"
|
||||
const miniSheet = CSS.parse(desRule).stylesheet.rules[0]
|
||||
if (ruleInds.length > 0) {
|
||||
sheet.stylesheet.rules[ruleInds[0]] = miniSheet
|
||||
const selector = potentialRules[rulename]["name"]
|
||||
const newRule = `${selector} {
|
||||
${potentialRules[rulename]["options"][optionname]}
|
||||
}`
|
||||
const miniSheet = CSS.parse(newRule).stylesheet.rules[0]
|
||||
|
||||
// Find pre-existing rules
|
||||
const oldRuleIndexes = findCssRules(selector, sheet)
|
||||
if (oldRuleIndexes.length > 0) {
|
||||
sheet.stylesheet.rules[oldRuleIndexes[0]] = miniSheet
|
||||
} else {
|
||||
sheet.stylesheet.rules = sheet.stylesheet.rules.concat(miniSheet)
|
||||
}
|
||||
|
||||
return sheet
|
||||
}
|
||||
|
||||
/** Apply rule to stylesheet. rulename, optionname identify a rule. They may be meta rules */
|
||||
export function changeCss(
|
||||
rulename: string,
|
||||
optionname: string,
|
||||
sheet: CSS.Stylesheet,
|
||||
): CSS.Stylesheet {
|
||||
if (rulename in metaRules) {
|
||||
for (let rule of Object.keys(metaRules[rulename][optionname])) {
|
||||
const metarule = metaRules[rulename][optionname]
|
||||
for (let rule of Object.keys(metarule)) {
|
||||
// have a metarule call itself for hours of fun
|
||||
sheet = changeCss(
|
||||
rule,
|
||||
metaRules[rulename][optionname][rule],
|
||||
sheet,
|
||||
)
|
||||
sheet = changeCss(rule, metarule[rule], sheet)
|
||||
}
|
||||
} else sheet = changeSingleCss(rulename, optionname, sheet)
|
||||
return sheet
|
||||
|
|
122
src/excmds.ts
122
src/excmds.ts
|
@ -87,7 +87,7 @@
|
|||
|
||||
// Shared
|
||||
import * as Messaging from "./messaging"
|
||||
import { l, browserBg, activeTabId } from "./lib/webext"
|
||||
import { l, browserBg, activeTabId, activeTabContainerId } from "./lib/webext"
|
||||
import state from "./state"
|
||||
import * as UrlUtil from "./url_util"
|
||||
import * as config from "./config"
|
||||
|
@ -97,7 +97,6 @@ import * as Logging from "./logging"
|
|||
const logger = new Logging.Logger("excmds")
|
||||
import Mark from "mark.js"
|
||||
import * as CSS from "css"
|
||||
import * as semverCompare from "semver-compare"
|
||||
|
||||
//#content_helper
|
||||
// {
|
||||
|
@ -118,6 +117,7 @@ import { ModeName } from "./state"
|
|||
import * as keydown from "./keydown_background"
|
||||
import { activeTab, firefoxVersionAtLeast, openInNewTab } from "./lib/webext"
|
||||
import * as CommandLineBackground from "./commandline_background"
|
||||
import * as rc from "./config_rc"
|
||||
|
||||
//#background_helper
|
||||
import * as Native from "./native_background"
|
||||
|
@ -167,7 +167,7 @@ export async function getinput() {
|
|||
*/
|
||||
//#background
|
||||
export async function editor() {
|
||||
if (!await nativegate()) return
|
||||
if (!await Native.nativegate()) return
|
||||
const file = (await Native.temp(await getinput())).content
|
||||
fillinput((await Native.editor(file)).content)
|
||||
// TODO: add annoying "This message was written with [Tridactyl](https://addons.mozilla.org/en-US/firefox/addon/tridactyl-vim/)"
|
||||
|
@ -217,17 +217,17 @@ export async function guiset(rule: string, option: string) {
|
|||
// Could potentially fall back to sending minimal example to clipboard if native not installed
|
||||
|
||||
// Check for native messenger and make sure we have a plausible profile directory
|
||||
if (!await nativegate("0.1.1")) return
|
||||
if (!await Native.nativegate("0.1.1")) return
|
||||
let profile_dir = ""
|
||||
if (config.get("profiledir") === "auto") {
|
||||
if (["linux", "openbsd", "mac"].includes((await browser.runtime.getPlatformInfo()).os)) profile_dir = await Native.getProfileDir()
|
||||
else {
|
||||
fillcmdline("Please set your profile directory (found on about:support) via `set profiledir [profile directory]`")
|
||||
return
|
||||
}
|
||||
} else profile_dir = config.get("profiledir")
|
||||
if (config.get("profiledir") === "auto" && ["linux", "openbsd", "mac"].includes((await browser.runtime.getPlatformInfo()).os)) {
|
||||
try {
|
||||
profile_dir = await Native.getProfileDir()
|
||||
} catch (e) {}
|
||||
} else {
|
||||
profile_dir = config.get("profiledir")
|
||||
}
|
||||
if (profile_dir == "") {
|
||||
logger.error("Profile not found.")
|
||||
fillcmdline("Please set your profile directory (found on about:support) via `set profiledir [profile directory]`")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -241,7 +241,8 @@ export async function guiset(rule: string, option: string) {
|
|||
// Modify and write new CSS
|
||||
if (cssstr === "") cssstr = `@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");`
|
||||
let stylesheet = CSS.parse(cssstr)
|
||||
let stylesheetDone = CSS.stringify(css_util.changeCss(rule, option, stylesheet))
|
||||
// Trim due to https://github.com/reworkcss/css/issues/114
|
||||
let stylesheetDone = CSS.stringify(css_util.changeCss(rule, option, stylesheet)).trim()
|
||||
Native.write(profile_dir + "/chrome/userChrome.css", stylesheetDone)
|
||||
}
|
||||
|
||||
|
@ -263,37 +264,11 @@ export function cssparse(...css: string[]) {
|
|||
//#background
|
||||
export async function nativeopen(url: string, ...firefoxArgs: string[]) {
|
||||
if (firefoxArgs.length === 0) firefoxArgs = ["--new-tab"]
|
||||
if (await nativegate()) {
|
||||
if (await Native.nativegate()) {
|
||||
Native.run(config.get("browser") + " " + firefoxArgs.join(" ") + " " + url)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used internally to gate off functions that use the native messenger. Gives a helpful error message in the command line if the native messenger is not installed, or is the wrong version.
|
||||
*/
|
||||
//#background
|
||||
export async function nativegate(version = "0", interactive = true): Promise<Boolean> {
|
||||
if (["win", "android"].includes((await browser.runtime.getPlatformInfo()).os)) {
|
||||
if (interactive == true) fillcmdline("# Tridactyl's native messenger doesn't support your operating system, yet.")
|
||||
return false
|
||||
}
|
||||
try {
|
||||
const actualVersion = await Native.getNativeMessengerVersion()
|
||||
if (actualVersion !== undefined) {
|
||||
if (semverCompare(version, actualVersion) > 0) {
|
||||
if (interactive == true) fillcmdline("# Please update to native messenger " + version + ", for example by running `:updatenative`.")
|
||||
// TODO: add update procedure and document here.
|
||||
return false
|
||||
}
|
||||
return true
|
||||
} else if (interactive == true) fillcmdline("# Native messenger not found. Please run `:installnative` and follow the instructions.")
|
||||
return false
|
||||
} catch (e) {
|
||||
if (interactive == true) fillcmdline("# Native messenger not found. Please run `:installnative` and follow the instructions.")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run command in /bin/sh (unless you're on Windows), and print the output in the command line. Non-zero exit codes and stderr are ignored, currently.
|
||||
*
|
||||
|
@ -337,6 +312,34 @@ export async function installnative() {
|
|||
fillcmdline("# Installation command copied to clipboard. Please paste and run it in your shell to install the native messenger.")
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs an RC file from disk.
|
||||
*
|
||||
* If no argument given, it will try to open ~/.tridactylrc, ~/.config/tridactylrc or $XDG_CONFIG_HOME/tridactyl/tridactylrc in reverse order.
|
||||
*
|
||||
* The RC file is just a bunch of Tridactyl excmds (i.e, the stuff on this help page). Settings persist in local storage; add `sanitise tridactyllocal tridactylsync` to make it more Vim like. There's an [example file](https://www.github.com/cmcaine/tridactyl/master/.tridactylrc) if you want it.
|
||||
*
|
||||
* @param fileArr the file to open. Must be an absolute path, but can contain environment variables and things like ~.
|
||||
*/
|
||||
//#background
|
||||
export async function source(...fileArr: string[]) {
|
||||
const file = fileArr.join(" ") || undefined
|
||||
if (await Native.nativegate("0.1.3")) if (!await rc.source(file)) logger.error("Could not find RC file")
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as [[source]] but suppresses all errors
|
||||
*/
|
||||
//#background
|
||||
export async function source_quiet(...fileArr: string[]) {
|
||||
try {
|
||||
const file = fileArr.join(" ") || undefined
|
||||
if (await Native.nativegate("0.1.3", false)) rc.source(file)
|
||||
} catch (e) {
|
||||
logger.info("Automatic loading of RC file failed.")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the native messenger if it is installed, using our GitHub repo. This is run every time Tridactyl is updated.
|
||||
*
|
||||
|
@ -344,7 +347,7 @@ export async function installnative() {
|
|||
*/
|
||||
//#background
|
||||
export async function updatenative(interactive = true) {
|
||||
if (await nativegate("0", interactive)) {
|
||||
if (await Native.nativegate("0", interactive)) {
|
||||
if ((await browser.runtime.getPlatformInfo()).os === "mac") {
|
||||
if (interactive) logger.error("Updating the native messenger on OSX is broken. Please use `:installnative` instead.")
|
||||
return
|
||||
|
@ -1244,7 +1247,10 @@ export async function tabopen(...addressarr: string[]) {
|
|||
} else if (address != "") url = forceURI(address)
|
||||
else url = forceURI(config.get("newtab"))
|
||||
|
||||
openInNewTab(url, { active })
|
||||
activeTabContainerId().then(containerId => {
|
||||
if (containerId && config.get("tabopencontaineraware") === "true") openInNewTab(url, { active: active, cookieStoreId: containerId })
|
||||
else openInNewTab(url, { active })
|
||||
})
|
||||
}
|
||||
|
||||
/** Resolve a tab index to the tab id of the corresponding tab in this window.
|
||||
|
@ -1405,18 +1411,6 @@ export async function undo() {
|
|||
}
|
||||
}
|
||||
|
||||
/** Synonym for [[tabclose]]. */
|
||||
//#background
|
||||
export async function quit() {
|
||||
tabclose()
|
||||
}
|
||||
|
||||
/** Convenience shortcut for [[quit]]. */
|
||||
//#background
|
||||
export async function q() {
|
||||
tabclose()
|
||||
}
|
||||
|
||||
/** Move the current tab to be just in front of the index specified.
|
||||
|
||||
Known bug: This supports relative movement, but autocomple doesn't know
|
||||
|
@ -1697,26 +1691,6 @@ export async function clipboard(excmd: "open" | "yank" | "yankshort" | "yankcano
|
|||
CommandLineBackground.hide()
|
||||
}
|
||||
|
||||
// {{{ Buffer/completion stuff
|
||||
|
||||
/** Equivalent to `fillcmdline buffer`
|
||||
|
||||
Sort of Vimperator alias
|
||||
*/
|
||||
//#background
|
||||
export async function tabs() {
|
||||
fillcmdline("Deprecated. If anyone actually uses this, they should file an issue on GitHub.")
|
||||
}
|
||||
|
||||
/** Equivalent to `fillcmdline buffer`
|
||||
|
||||
Sort of Vimperator alias
|
||||
*/
|
||||
//#background
|
||||
export async function buffers() {
|
||||
tabs()
|
||||
}
|
||||
|
||||
/** Change active tab.
|
||||
|
||||
@param index
|
||||
|
|
|
@ -537,7 +537,7 @@ const HINTTAGS_saveable = `
|
|||
[href]:not([href='#'])
|
||||
`
|
||||
|
||||
import { openInNewTab } from "./lib/webext"
|
||||
import { openInNewTab, activeTabContainerId } from "./lib/webext"
|
||||
|
||||
/** if `target === _blank` clicking the link is treated as opening a popup and is blocked. Use webext API to avoid that. */
|
||||
function simulateClick(target: HTMLElement) {
|
||||
|
@ -550,7 +550,18 @@ function simulateClick(target: HTMLElement) {
|
|||
(target as HTMLAnchorElement).target === "_blank" ||
|
||||
(target as HTMLAnchorElement).target === "_new"
|
||||
) {
|
||||
openInNewTab((target as HTMLAnchorElement).href, { related: true })
|
||||
// Try to open the new tab in the same container as the current one.
|
||||
activeTabContainerId().then(containerId => {
|
||||
if (containerId)
|
||||
openInNewTab((target as HTMLAnchorElement).href, {
|
||||
related: true,
|
||||
cookieStoreId: containerId,
|
||||
})
|
||||
else
|
||||
openInNewTab((target as HTMLAnchorElement).href, {
|
||||
related: true,
|
||||
})
|
||||
})
|
||||
} else {
|
||||
DOM.mouseEvent(target, "click")
|
||||
// DOM.focus has additional logic for focusing inputs
|
||||
|
@ -563,10 +574,21 @@ function hintPageOpenInBackground(selectors = HINTTAGS_selectors) {
|
|||
hint.target.focus()
|
||||
if (hint.target.href) {
|
||||
// Try to open with the webext API. If that fails, simulate a click on this page anyway.
|
||||
openInNewTab(hint.target.href, {
|
||||
active: false,
|
||||
related: true,
|
||||
}).catch(() => simulateClick(hint.target))
|
||||
// Try to open the new tab in the same container as the current one.
|
||||
activeTabContainerId().then(containerId => {
|
||||
if (containerId) {
|
||||
openInNewTab(hint.target.href, {
|
||||
active: false,
|
||||
related: true,
|
||||
cookieStoreId: containerId,
|
||||
}).catch(() => simulateClick(hint.target))
|
||||
} else {
|
||||
openInNewTab(hint.target.href, {
|
||||
active: false,
|
||||
related: true,
|
||||
}).catch(() => simulateClick(hint.target))
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// This is to mirror vimperator behaviour.
|
||||
simulateClick(hint.target)
|
||||
|
|
|
@ -67,6 +67,11 @@ export async function activeTabId() {
|
|||
return (await activeTab()).id
|
||||
}
|
||||
|
||||
//#background_helper
|
||||
export async function activeTabContainerId() {
|
||||
return (await activeTab()).cookieStoreId
|
||||
}
|
||||
|
||||
/** Compare major firefox versions */
|
||||
export async function firefoxVersionAtLeast(desiredmajor: number) {
|
||||
const versionstr = (await browserBg.runtime.getBrowserInfo()).version
|
||||
|
@ -88,12 +93,17 @@ export async function firefoxVersionAtLeast(desiredmajor: number) {
|
|||
*/
|
||||
export async function openInNewTab(
|
||||
url: string,
|
||||
kwargs: { active?; related? } = { active: true, related: false },
|
||||
kwargs: { active?; related?; cookieStoreId? } = {
|
||||
active: true,
|
||||
related: false,
|
||||
cookieStoreId: undefined,
|
||||
},
|
||||
) {
|
||||
const thisTab = await activeTab()
|
||||
const options: any = {
|
||||
active: kwargs.active,
|
||||
url,
|
||||
cookieStoreId: kwargs.cookieStoreId,
|
||||
}
|
||||
|
||||
// Be nice to behrmann, #342
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Tridactyl",
|
||||
"version": "1.10.1",
|
||||
"version": "1.12.0",
|
||||
"icons": {
|
||||
"64": "static/logo/Tridactyl_64px.png",
|
||||
"100": "static/logo/Tridactyl_100px.png",
|
||||
|
@ -43,6 +43,8 @@
|
|||
"bookmarks",
|
||||
"browsingData",
|
||||
"contextMenus",
|
||||
"contextualIdentities",
|
||||
"cookies",
|
||||
"clipboardWrite",
|
||||
"clipboardRead",
|
||||
"downloads",
|
||||
|
|
|
@ -2,13 +2,23 @@
|
|||
* Background functions for the native messenger interface
|
||||
*/
|
||||
|
||||
import * as semverCompare from "semver-compare"
|
||||
import * as config from "./config"
|
||||
|
||||
import Logger from "./logging"
|
||||
const logger = new Logger("native")
|
||||
|
||||
const NATIVE_NAME = "tridactyl"
|
||||
type MessageCommand = "version" | "run" | "read" | "write" | "temp" | "mkdir"
|
||||
type MessageCommand =
|
||||
| "version"
|
||||
| "run"
|
||||
| "read"
|
||||
| "write"
|
||||
| "temp"
|
||||
| "mkdir"
|
||||
| "eval"
|
||||
| "getconfig"
|
||||
| "env"
|
||||
interface MessageResp {
|
||||
cmd: string
|
||||
version: number | null
|
||||
|
@ -35,12 +45,23 @@ async function sendNativeMsg(
|
|||
return resp as MessageResp
|
||||
} catch (e) {
|
||||
if (!quiet) {
|
||||
logger.error(`Error sending native message:`, e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function getrc(): Promise<string> {
|
||||
const res = await sendNativeMsg("getconfig", {})
|
||||
|
||||
if (res.content && !res.error) {
|
||||
logger.info(`Successfully retrieved fs config:\n${res.content}`)
|
||||
return res.content
|
||||
} else {
|
||||
// Have to make this a warning as async exceptions apparently don't get caught
|
||||
logger.info(`Error in retrieving config: ${res.error}`)
|
||||
}
|
||||
}
|
||||
|
||||
export async function getNativeMessengerVersion(
|
||||
quiet = false,
|
||||
): Promise<number> {
|
||||
|
@ -80,10 +101,12 @@ export async function getBestEditor(): Promise<string> {
|
|||
"xterm -class tridactyl_editor -e",
|
||||
"uxterm -class tridactyl_editor -e",
|
||||
"urxvt -e",
|
||||
// "terminator -e", // NB: requires command to be in quotes, which breaks the others
|
||||
// so terminator is not supported.
|
||||
"alacritty -e", // alacritty is nice but takes ages to start and doesn't support class
|
||||
"cool-retro-term -e",
|
||||
// Terminator and termite require -e commands to be in quotes, hence the extra quote at the end.
|
||||
// The closing quote is implemented in the editor function.
|
||||
'terminator -e "',
|
||||
'termite --class tridactyl_editor -e "',
|
||||
"dbus-launch gnome-terminal --",
|
||||
// I wanted to put hyper.js here as a joke but you can't start it running a command,
|
||||
// which is a far better joke: a terminal emulator that you can't send commands to.
|
||||
|
@ -120,6 +143,59 @@ export async function getBestEditor(): Promise<string> {
|
|||
return cmd
|
||||
}
|
||||
|
||||
/**
|
||||
* Used internally to gate off functions that use the native messenger. Gives a
|
||||
* helpful error message in the command line if the native messenger is not
|
||||
* installed, or is the wrong version.
|
||||
*
|
||||
* @arg version: A string representing the minimal required version.
|
||||
* @arg interactive: True if a message should be displayed on version mismatch.
|
||||
* @return false if the required version is higher than the currently available
|
||||
* native messenger version.
|
||||
*/
|
||||
export async function nativegate(
|
||||
version = "0",
|
||||
interactive = true,
|
||||
): Promise<Boolean> {
|
||||
if (
|
||||
["win", "android"].includes(
|
||||
(await browser.runtime.getPlatformInfo()).os,
|
||||
)
|
||||
) {
|
||||
if (interactive == true)
|
||||
logger.error(
|
||||
"# Tridactyl's native messenger doesn't support your operating system, yet.",
|
||||
)
|
||||
return false
|
||||
}
|
||||
try {
|
||||
const actualVersion = await getNativeMessengerVersion()
|
||||
if (actualVersion !== undefined) {
|
||||
if (semverCompare(version, actualVersion) > 0) {
|
||||
if (interactive == true)
|
||||
logger.error(
|
||||
"# Please update to native messenger " +
|
||||
version +
|
||||
", for example by running `:updatenative`.",
|
||||
)
|
||||
// TODO: add update procedure and document here.
|
||||
return false
|
||||
}
|
||||
return true
|
||||
} else if (interactive == true)
|
||||
logger.error(
|
||||
"# Native messenger not found. Please run `:installnative` and follow the instructions.",
|
||||
)
|
||||
return false
|
||||
} catch (e) {
|
||||
if (interactive == true)
|
||||
logger.error(
|
||||
"# Native messenger not found. Please run `:installnative` and follow the instructions.",
|
||||
)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export async function inpath(cmd) {
|
||||
return (await run("which " + cmd.split(" ")[0])).code === 0
|
||||
}
|
||||
|
@ -142,7 +218,11 @@ export async function editor(file: string, content?: string) {
|
|||
config.get("editorcmd") == "auto"
|
||||
? await getBestEditor()
|
||||
: config.get("editorcmd")
|
||||
await run(editorcmd + " " + file)
|
||||
// Dirty hacks for termite and terminator support part 2.
|
||||
const e = editorcmd.split(" ")[0]
|
||||
if (e === "termite" || e === "terminator") {
|
||||
await run(editorcmd + " " + file + '"')
|
||||
} else await run(editorcmd + " " + file)
|
||||
return await read(file)
|
||||
}
|
||||
|
||||
|
@ -161,24 +241,84 @@ export async function mkdir(dir: string, exist_ok: boolean) {
|
|||
export async function temp(content: string) {
|
||||
return sendNativeMsg("temp", { content })
|
||||
}
|
||||
|
||||
export async function run(command: string) {
|
||||
let msg = await sendNativeMsg("run", { command })
|
||||
logger.info(msg)
|
||||
return msg
|
||||
}
|
||||
|
||||
/** Evaluates a string in the native messenger. This has to be python code. If
|
||||
* you want to run shell strings, use run() instead.
|
||||
*/
|
||||
export async function pyeval(command: string): Promise<MessageResp> {
|
||||
return sendNativeMsg("eval", { command })
|
||||
}
|
||||
|
||||
export async function getenv(variable: string) {
|
||||
let v = await getNativeMessengerVersion()
|
||||
if (!await nativegate("0.1.2", false)) {
|
||||
throw `Error: getenv needs native messenger v>=0.1.2. Current: ${v}`
|
||||
}
|
||||
return (await sendNativeMsg("env", { var: variable })).content
|
||||
}
|
||||
|
||||
/** This returns the commandline that was used to start firefox.
|
||||
You'll get both firefox binary (not necessarily an absolute path) and flags */
|
||||
export async function ffargs(): Promise<string[]> {
|
||||
// Using ' and + rather that ` because we don't want newlines
|
||||
let output = await pyeval(
|
||||
'handleMessage({"cmd": "run", ' +
|
||||
'"command": "ps -p " + str(os.getppid()) + " -oargs="})["content"]',
|
||||
)
|
||||
return output.content.trim().split(" ")
|
||||
}
|
||||
|
||||
export async function getProfileDir() {
|
||||
// First, see if we can get the profile from the arguments that were given
|
||||
// to Firefox
|
||||
let args = await ffargs()
|
||||
|
||||
// --profile <path>: Start with profile at <path>
|
||||
let prof = args.indexOf("--profile")
|
||||
if (prof >= 0) return args[prof + 1]
|
||||
|
||||
// -P <profile>: Start with <profile>
|
||||
// -P : Start with profile manager
|
||||
// Apparently, this argument is case-insensitive
|
||||
let profileName = "*"
|
||||
prof = args.indexOf("-P")
|
||||
if (prof < 0) prof = args.indexOf("-p")
|
||||
// args.length -1 because we need to make sure -P was given a value
|
||||
if (prof >= 0 && prof < args.length - 1) profileName = args[prof + 1]
|
||||
|
||||
// Find active profile directory automatically by seeing where the lock exists
|
||||
let hacky_profile_finder = "find ../../../.mozilla/firefox -name lock"
|
||||
let home = "../../.."
|
||||
try {
|
||||
// We try not to use a relative path because ~/.local (the directory where
|
||||
// the native messenger currently sits) might actually be a symlink
|
||||
home = await getenv("HOME")
|
||||
} catch (e) {}
|
||||
let hacky_profile_finder = `find "${home}/.mozilla/firefox" -maxdepth 2 -path '*.${profileName}/lock'`
|
||||
if ((await browser.runtime.getPlatformInfo()).os === "mac")
|
||||
hacky_profile_finder =
|
||||
"find ../../../Library/'Application Support'/Firefox/Profiles -maxdepth 2 -name .parentlock"
|
||||
let profilecmd = await run(hacky_profile_finder)
|
||||
if (profilecmd.code != 0) {
|
||||
return ""
|
||||
} else
|
||||
return profilecmd.content
|
||||
.split("/")
|
||||
.slice(0, -1)
|
||||
.join("/")
|
||||
throw new Error("Profile not found")
|
||||
} else {
|
||||
// Remove trailing newline
|
||||
profilecmd.content = profilecmd.content.trim()
|
||||
if (profilecmd.content.split("\n").length > 1) {
|
||||
throw new Error(
|
||||
"Multiple profiles in use. Can't tell which one you want. `set profiledir`, close other Firefox profiles or remove zombie lock files.",
|
||||
)
|
||||
} else {
|
||||
// Get parent directory of lock file
|
||||
return profilecmd.content
|
||||
.split("/")
|
||||
.slice(0, -1)
|
||||
.join("/")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,10 @@ import { hasModifiers } from "../keyseq"
|
|||
// Placeholder - should be moved into generic parser
|
||||
export function parser(keys) {
|
||||
const response = { keys: [], exstr: undefined }
|
||||
if (keys[0].shiftKey && keys[0].key === "Insert") {
|
||||
if (
|
||||
(keys[0].shiftKey && keys[0].key === "Insert") ||
|
||||
(keys[0].altKey && keys[0].ctrlKey && keys[0].key === "Escape")
|
||||
) {
|
||||
return { keys: [], exstr: "mode normal" }
|
||||
}
|
||||
return { keys: [], exstr: undefined }
|
||||
|
|
32
src/requests.ts
Normal file
32
src/requests.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
import * as config from "./config"
|
||||
|
||||
export function addurltocsp(response) {
|
||||
let headers = response["responseHeaders"]
|
||||
let cspind = headers.findIndex(
|
||||
header => header.name == "Content-Security-Policy",
|
||||
)
|
||||
// if it's found
|
||||
if (cspind > -1) {
|
||||
// Split the csp header up so we can manage it individually.
|
||||
let csparr = [headers[cspind]["value"].split("; ")][0]
|
||||
|
||||
for (let i = 0; i < csparr.length; i++) {
|
||||
// Add 'unsafe-inline' as a directive since we use it
|
||||
if (csparr[i].indexOf("style-src") > -1) {
|
||||
if (csparr[i].indexOf("'self'") > -1) {
|
||||
csparr[i] = csparr[i].replace(
|
||||
"'self'",
|
||||
"'self' 'unsafe-inline'",
|
||||
)
|
||||
}
|
||||
}
|
||||
// Remove the element if it's a sandbox directive
|
||||
if (csparr[i] === "sandbox") {
|
||||
csparr.splice(i, 1)
|
||||
}
|
||||
}
|
||||
// Join the header up after clobberin'
|
||||
headers[cspind]["value"] = csparr.join("; ")
|
||||
}
|
||||
return { responseHeaders: headers }
|
||||
}
|
|
@ -29,7 +29,6 @@ input[id^="spoiler"]:checked + label {
|
|||
background: #ccc;
|
||||
}
|
||||
input[id^="spoiler"] ~ .spoiler {
|
||||
width: 90%;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
opacity: 0;
|
||||
|
|
|
@ -12,8 +12,6 @@ Tridactyl has to override your new tab page due to WebExtension limitations. You
|
|||
|
||||
- If you're enjoying Tridactyl (or not), please leave a review on [addons.mozilla.org][amo].
|
||||
|
||||
- **Breaking change to default settings:** ignore mode is now bound to `<S-Insert>` for both entering and leaving the mode. Previous binds are unbound.
|
||||
|
||||
- **NB:** Tridactyl can now run external programs on Linux and OSX if you decide to install an additional executable. Just run `:installnative` to get going, and then Ctrl-i `<C-i>` in a text box to open your editor.
|
||||
|
||||
|
||||
|
@ -44,7 +42,7 @@ REPLACE_ME_WITH_THE_CHANGE_LOG_USING_SED
|
|||
|
||||
- You can only navigate to most about:*\file:* pages if you have Tridactyl's native executable installed.
|
||||
- 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]].
|
||||
- You can change the Firefox GUI with `guiset` (e.g. `guiset gui none`) if you have the native messenger installed, or you can do it yourself by changing your userChrome. There is an example file available on our repository [[2]].
|
||||
- Tridactyl cannot capture key presses until web pages are loaded. You can use `:reloadall` to reload all tabs to make life more bearable, or flip `browser.sessionstore.restore_tabs_lazily` to false in `about:config`.
|
||||
|
||||
## Why do I see this here?
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<html lang="en" style="display: none;">
|
||||
<head>
|
||||
<script src="newtab.js"></script>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="newtab.css">
|
||||
<link rel="stylesheet" href="content.css">
|
||||
|
|
|
@ -889,7 +889,7 @@ body {
|
|||
}
|
||||
|
||||
a {
|
||||
color: green;
|
||||
color: #05a805;
|
||||
}
|
||||
|
||||
code {
|
||||
|
|
4
src/tridactyl.d.ts
vendored
4
src/tridactyl.d.ts
vendored
|
@ -50,3 +50,7 @@ declare function html(
|
|||
strings: TemplateStringsArray,
|
||||
...values: any[]
|
||||
): HTMLElement
|
||||
|
||||
declare namespace browser.webRequest {
|
||||
function filterResponseData(requestId: string): any
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue