Merge branch 'master' into quicker_ramda

This commit is contained in:
Oliver Blanthorn 2021-05-02 12:22:48 +01:00 committed by GitHub
commit 77dee7869a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 194 additions and 153 deletions

2
.gitignore vendored
View file

@ -15,3 +15,5 @@ compiler/**/*.js
.*.generated.ts
.tmp/
.DS_Store
.build_cache/
yarn-error.log

View file

@ -86,6 +86,9 @@ command hint_focus hint -;
" Open right click menu on links
bind ;C composite hint_focus; !s xdotool key Menu
" Suspend / "discard" all tabs - handy for stretching out battery life
command discardall jsb browser.tabs.query({}).then(ts => browser.tabs.discard(ts.map(t=>t.id)))
" Julia docs' built in search is bad
set searchurls.julia https://www.google.com/search?q=site:http://docs.julialang.org/en/v1%20

View file

@ -13,7 +13,7 @@ module.exports = {
"ts-jest": {
tsConfig: {
...tsConfig.compilerOptions,
types: ["jest", "node", "web-ext-types"]
types: ["jest", "node", "@types/firefox-webext-browser"]
},
diagnostics: {
ignoreCodes: [151001]

View file

@ -41,7 +41,7 @@
"eslint": "^7.25.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsdoc": "^32.3.3",
"eslint-plugin-jsdoc": "^32.3.4",
"eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-sonarjs": "^0.5.0",
"geckodriver": "^1.22.3",
@ -62,7 +62,6 @@
"typedoc": "^0.19.2",
"typescript": "^3.9.9",
"web-ext": "^6.0.0",
"web-ext-types": "^3.2.1",
"webpack": "^5.36.1",
"webpack-cli": "^4.6.0"
},

View file

@ -4,10 +4,18 @@ set -e
err() { echo "error: line $(caller)"; }
trap err ERR
mkdir -p .build_cache
cd src/static
authors="../../build/static/authors.html"
sed "/REPLACETHIS/,$ d" authors.html > "$authors"
git shortlog -sn HEAD | cut -c8- | awk '!seen[$0]++' | sed 's/^/<p>/' | sed 's/$/<\/p>/' >> "$authors"
# If we're in a git repo, refresh the cache
if [ -d "../../.git/" ]; then
git shortlog -sn HEAD | cut -c8- | awk '!seen[$0]++' | sed 's/^/<p>/' | sed 's/$/<\/p>/' > ../../.build_cache/authors
fi
cat ../../.build_cache/authors >> "$authors"
sed "1,/REPLACETHIS/ d" authors.html >> "$authors"

View file

@ -4,7 +4,7 @@ set -e
sign_and_submit() {
# Don't trust the return value of web-ext sign.
(source AMOKEYS && (web-ext sign -s build --api-key $AMOKEY --api-secret $AMOSECRET "$@" || true))
(source AMOKEYS && (yarn run web-ext sign -s build --api-key "$AMOKEY" --api-secret "$AMOSECRET" "$@" || true))
}
publish_beta_nonewtab() {
@ -23,6 +23,7 @@ publish_beta() {
scripts/version.js beta
sed 's/"name": "Tridactyl"/"name": "Tridactyl: Beta"/' -i build/manifest.json
sign_and_submit
tar --exclude-from=<(grep -v .build_cache/ .gitignore) --exclude-vcs -czf ../../public_html/betas/tridactyl_source_beta.tar.gz .
}
build_no_sign_beta(){
@ -31,9 +32,9 @@ build_no_sign_beta(){
scripts/version.js beta
sed 's/"name": "Tridactyl"/"name": "Tridactyl: Beta"/' -i build/manifest.json
mkdir -p web-ext-artifacts
$(yarn bin)/web-ext build --source-dir ./build --overwrite-dest
yarn run web-ext build --source-dir ./build --overwrite-dest
for f in web-ext-artifacts/*.zip; do
mv $f ${f%.zip}.xpi
mv "$f" "${f%.zip}".xpi
done
}
@ -42,9 +43,9 @@ build_no_sign_stable(){
yarn run build --no-native
sed 's/tridactyl.vim.betas@cmcaine/tridactyl.vim@cmcaine/' -i build/manifest.json
mkdir -p web-ext-artifacts
$(yarn bin)/web-ext build --source-dir ./build --overwrite-dest
yarn run web-ext build --source-dir ./build --overwrite-dest
for f in web-ext-artifacts/*.zip; do
mv $f ${f%.zip}.xpi
mv "$f" "${f%.zip}".xpi
done
}
@ -53,7 +54,7 @@ publish_stable() {
yarn run build --no-native
sed 's/tridactyl.vim.betas@cmcaine/tridactyl.vim@cmcaine/' -i build/manifest.json
sign_and_submit
tar --exclude-from=.gitignore -czf ../../public_html/betas/tridactyl_source.tar.gz .
tar --exclude-from=<(grep -v .build_cache/ .gitignore) --exclude-vcs -czf ../../public_html/betas/tridactyl_source.tar.gz .
}
case $1 in
@ -61,5 +62,6 @@ case $1 in
nosignstable) build_no_sign_stable;;
nosignbeta) build_no_sign_beta;;
nonewtab) publish_beta_nonewtab;;
*|beta) publish_beta;;
beta) publish_beta;;
*) publish_beta;;
esac

View file

@ -1,6 +1,7 @@
#!/usr/bin/env node
const { exec } = require("child_process")
const fs = require("fs")
function bump_version(versionstr, component = 2) {
const versionarr = versionstr.split(".")
@ -12,21 +13,37 @@ function bump_version(versionstr, component = 2) {
}
async function add_beta(versionstr) {
return new Promise((resolve, err) => {
exec("git rev-list --count HEAD", (execerr, stdout, stderr) => {
if (execerr) err(execerr)
resolve(versionstr + "pre" + stdout.trim())
await fs.promises.mkdir(".build_cache", {recursive: true})
try {
await fs.promises.access(".git")
await new Promise((resolve, err) => {
exec("git rev-list --count HEAD > .build_cache/count", (execerr, stdout, stderr) => {
if (execerr) err(execerr)
resolve(stdout.trim())
})
})
})
}
catch {
; // Not in a git directory - don't do anything
}
return versionstr + "pre" + (await fs.promises.readFile(".build_cache/count", {encoding: "utf8"})).trim()
}
async function get_hash() {
return new Promise((resolve, err) => {
exec("git rev-parse --short HEAD", (execerr, stdout, stderr) => {
if (execerr) err(execerr)
resolve(stdout.trim())
await fs.promises.mkdir(".build_cache", {recursive: true})
try {
await fs.promises.access(".git")
await new Promise((resolve, err) => {
exec("git rev-parse --short HEAD > .build_cache/hash", (execerr, stdout, stderr) => {
if (execerr) err(execerr)
resolve(stdout.trim())
})
})
})
}
catch {
; // Not in a git directory - don't do anything
}
return (await fs.promises.readFile(".build_cache/hash", {encoding: "utf8"})).trim()
}
function make_update_json(versionstr) {
@ -102,7 +119,7 @@ async function main() {
make_update_json(manifest.version),
)
} catch(e) {
console.warn("updates.json wasn't updated: " + e)
console.warn("Unless you're the buildbot, ignore this error: " + e)
}
// Save manifest.json

View file

@ -1,5 +1,5 @@
import { messageActiveTab } from "@src/lib/messaging.ts"
import * as _EditorCmds from "@src/lib/editor.ts"
import { messageActiveTab } from "@src/lib/messaging"
import * as _EditorCmds from "@src/lib/editor"
type cmdsType = typeof _EditorCmds
type ArgumentsType<T> = T extends (elem, ...args: infer U) => any ? U : never

View file

@ -29,7 +29,7 @@ export abstract class CompletionOption {
/** What to fill into cmdline */
value: string
/** Control presentation of the option */
state: OptionState
abstract state: OptionState
}
export abstract class CompletionSource {
@ -94,7 +94,7 @@ export abstract class CompletionSource {
/** Update [[node]] to display completions relevant to exstr */
public abstract filter(exstr: string): Promise<void>
abstract async next(inc?: number): Promise<boolean>
abstract next(inc?: number): Promise<boolean>
}
// Default classes

View file

@ -1,4 +1,4 @@
import { browserBg } from "@src/lib/webext.ts"
import { browserBg } from "@src/lib/webext"
import * as Completions from "@src/completions"
import * as config from "@src/lib/config"

View file

@ -1,5 +1,5 @@
import * as Perf from "@src/perf"
import { browserBg } from "@src/lib/webext.ts"
import { browserBg } from "@src/lib/webext"
import { enumerate } from "@src/lib/itertools"
import * as Containers from "@src/lib/containers"
import * as Completions from "@src/completions"

View file

@ -1,7 +1,8 @@
import { browserBg } from "@src/lib/webext.ts"
import { browserBg } from "@src/lib/webext"
import * as Completions from "@src/completions"
class WindowCompletionOption extends Completions.CompletionOptionHTML
class WindowCompletionOption
extends Completions.CompletionOptionHTML
implements Completions.CompletionOptionFuse {
public fuseKeys = []

View file

@ -2,9 +2,9 @@ import {
messageOwnTab,
addListener,
attributeCaller,
} from "@src/lib/messaging.ts"
} from "@src/lib/messaging"
import * as DOM from "@src/lib/dom"
import * as _EditorCmds from "@src/lib/editor.ts"
import * as _EditorCmds from "@src/lib/editor"
export const EditorCmds = new Proxy(_EditorCmds, {
get(target, property) {

View file

@ -402,8 +402,8 @@ interface Hintables {
export function hintPage(
hintableElements: Hintables[],
onSelect: HintSelectedCallback,
resolve = () => {}, // eslint-disable-line @typescript-eslint/no-empty-function
reject = () => {}, // eslint-disable-line @typescript-eslint/no-empty-function
resolve: (x?) => void = () => {}, // eslint-disable-line @typescript-eslint/no-empty-function
reject: (x?) => void = () => {}, // eslint-disable-line @typescript-eslint/no-empty-function
rapid = false,
) {
const buildHints: HintBuilder = defaultHintBuilder()

View file

@ -7,6 +7,7 @@
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
export function jack_in() {
// chinese characters - taken from the unicode charset
const chinese = "田由甲申甴电甶男甸甹町画甼甽甾甿畀畁畂畃畄畅畆畇畈畉畊畋界畍畎畏畐畑".split("")
@ -14,7 +15,6 @@ export function jack_in() {
rain(makeBlock(), chinese, colour)
}
export function music() {
// music characters - taken from the unicode charset
const music = "𝄞𝄟𝄰𝅘𝅥𝅮𝅘𝅥𝅯𝅘𝅥𝅰𝄽".split("")
@ -32,17 +32,98 @@ function makeBlock() {
overlaydiv.style.position = "fixed"
overlaydiv.style.display = "block"
overlaydiv.style.width = String(window.innerWidth)
overlaydiv.style.height = String(window.innerHeight)
overlaydiv.style.top = "0"
overlaydiv.style.left = "0"
overlaydiv.style.right = "0"
overlaydiv.style.bottom = "0"
overlaydiv.style.height = String(document.documentElement.scrollHeight)
overlaydiv.style.top = "0px"
overlaydiv.style.bottom = "0px"
overlaydiv.style.left = "0px"
overlaydiv.style.right = "0px"
overlaydiv.style.zIndex = "1000"
overlaydiv.style.opacity = "0.5"
document.body.appendChild(overlaydiv)
return overlaydiv
}
export function drawable() {
eraser = false
make_drawable(makeBlock())
}
const clickX = []
const clickY = []
const clickDrag = []
let ink
let eraser = false;
export function eraser_toggle() {
eraser = !eraser
}
function addClick(x, y, dragging) {
clickX.push(x)
clickY.push(y)
clickDrag.push(dragging)
}
function redraw(context) {
if(eraser) {
context.globalCompositeOperation = "destination-out"
context.lineWidth = 18
} else {
context.globalCompositeOperation = "source-over"
context.lineWidth = 3
}
context.strokeStyle = "#000000"
context.lineJoin = "miter"
for(let i=0; i < clickX.length; i++) {
context.beginPath()
if(clickDrag[i] && i){
context.moveTo(clickX[i-1], clickY[i-1])
} else {
context.moveTo(clickX[i]-1, clickY[i])
}
context.lineTo(clickX[i], clickY[i])
context.closePath()
context.stroke()
}
}
function handleDown(e, context){
ink = true
addClick(e.pageX, e.pageY, false)
redraw(context)
e.preventDefault()
e.stopPropagation()
}
function handleUp(e){
ink = false
clickX.length = 0
clickY.length = 0
clickDrag.length = 0
e.stopPropagation()
e.preventDefault()
}
function handleMove(e, context) {
if(ink){
addClick(e.pageX, e.pageY, true);
redraw(context);
}
e.preventDefault()
e.stopPropagation()
}
function make_drawable(overlaydiv) {
overlaydiv.style.position = "absolute"
overlaydiv.style.opacity = "0.8"
const c = document.createElement("canvas")
overlaydiv.appendChild(c)
const context = c.getContext("2d")
// making the canvas full screen
c.height = document.documentElement.scrollHeight
c.width = window.innerWidth*0.98 // workaround to fix canvas overflow
c.style.touchAction = "none" // for pen tablet to work
c.addEventListener("pointerdown", e=>handleDown(e,context))
c.addEventListener("pointerup", handleUp)
c.addEventListener("pointermove", e=>handleMove(e,context))
}
export function removeBlock() {
Array.from(document.getElementsByClassName("_tridactyl_no_mouse_")).map((el: Element & { intid?: number | null}) => {
if(typeof el.intid === "number") {

View file

@ -1633,11 +1633,30 @@ export function snow_mouse_mode() {
export function pied_piper_mouse_mode() {
toys.music()
}
/**
* Drawable variant of [[no_mouse_mode]]
* In this mode, you can use the mouse or a digital stylus to draw. To switch to an eraser, use [[drawingerasertoggle]]
* Use [[mouse_mode]] to return, or refresh page.
* Suggested usage: `autocmd DocLoad .* drawingstart
*
* **Warning**: Windows Ink enabled input devices don't work, disable it for your browser, or use a mouse.
*/
//#content
export function drawingstart() {
toys.drawable()
}
/**
* Switch between pen and eraser for [[drawingstart]]
* Suggested usage: `bind e drawingerasertoggle`. If you have a digital pen, map the button to `e` to switch easily.
*/
//#content
export function drawingerasertoggle() {
toys.eraser_toggle()
}
/**
* Revert any variant of the [[no_mouse_mode]]
*
* Suggested usage: `bind <C-\> mouse_mode` with the autocmd mentioned in [[no_mouse_mode]].
* Suggested usage: `bind <C-\> mouse_mode` with the autocmd mentioned in [[no_mouse_mode]] or [[drawingstart]].
*/
//#content
export function mouse_mode() {
@ -3254,7 +3273,7 @@ export async function fillcmdline_tmp(ms: number, ...strarr: string[]) {
const str = strarr.join(" ")
showcmdline(false)
Messaging.messageOwnTab("commandline_frame", "fillcmdline", [strarr.join(" "), false, false])
return new Promise(resolve =>
return new Promise<void>(resolve =>
setTimeout(async () => {
if ((await Messaging.messageOwnTab("commandline_frame", "getContent", [])) === str) {
CommandLineContent.hide_and_blur()
@ -4742,7 +4761,11 @@ export function buildFilterConfigs(filters: string[]): Perf.StatsFilterConfig[]
} else if (filter === ":measure") {
return { kind: "eventType", eventType: "measure" }
} else {
return { kind: "functionName", functionName: name }
// This used to say `functionName: name`
// which didn't seem to exist anywhere
//
// So at least we return something now
return { kind: "functionName", functionName: filter }
}
},
)

View file

@ -609,6 +609,7 @@ export class default_config {
"mktridactylrc!": "mktridactylrc -f",
mpvsafe:
"js -p tri.excmds.shellescape(JS_ARG).then(url => tri.excmds.exclaim_quiet('mpv --no-terminal ' + url))",
drawingstop: "no_mouse_mode",
exto: "extoptions",
extpreferences: "extoptions",
extp: "extpreferences",

View file

@ -16,11 +16,11 @@ export const KNOWN_EXTENSIONS: { [name: string]: string } = {
/** List of currently installed extensions.
*/
const installedExtensions: {
[id: string]: browser.management.IExtensionInfo
[id: string]: browser.management.ExtensionInfo
} = {}
function updateExtensionInfo(
extension: browser.management.IExtensionInfo,
extension: browser.management.ExtensionInfo,
): void {
installedExtensions[extension.id] = extension
}

View file

@ -10,7 +10,12 @@ export function inContentScript() {
export function getTriVersion() {
const manifest = browser.runtime.getManifest()
return manifest.version_name
// version_name only really exists in Chrome
// but we're using it anyway for our own purposes
return (manifest as browser._manifest.WebExtensionManifest & {
version_name: string
}).version_name
}
export function getPrettyTriVersion() {

96
src/tridactyl.d.ts vendored
View file

@ -89,102 +89,6 @@ interface WebExtEventBase<
hasListener(cb: TCallback): boolean
}
type WebExtEvent<TCallback extends (...args: any[]) => any> = WebExtEventBase<
(callback: TCallback) => void,
TCallback
>
declare namespace browser.management {
/* management types */
/** Information about an icon belonging to an extension. */
interface IconInfo {
/**
* A number representing the width and height of the icon. Likely values include (but are not limited to) 128,
* 48, 24, and 16.
*/
size: number
/**
* The URL for this icon image. To display a grayscale version of the icon (to indicate that an extension is
* disabled, for example), append `?grayscale=true` to the URL.
*/
url: string
}
/** A reason the item is disabled. */
type ExtensionDisabledReason = "unknown" | "permissions_increase"
/** The type of this extension. Will always be 'extension'. */
type ExtensionType = "extension" | "theme"
/**
* How the extension was installed. One of
* `development`: The extension was loaded unpacked in developer mode,
* `normal`: The extension was installed normally via an .xpi file,
* `sideload`: The extension was installed by other software on the machine,
* `other`: The extension was installed by other means.
*/
type ExtensionInstallType = "development" | "normal" | "sideload" | "other"
/** Information about an installed extension. */
interface IExtensionInfo {
/** The extension's unique identifier. */
id: string
/** The name of this extension. */
name: string
/** A short version of the name of this extension. */
shortName?: string
/** The description of this extension. */
description: string
/** The version of this extension. */
version: string
/** The version name of this extension if the manifest specified one. */
versionName?: string
/** Whether this extension can be disabled or uninstalled by the user. */
mayDisable: boolean
/** Whether it is currently enabled or disabled. */
enabled: boolean
/** A reason the item is disabled. */
disabledReason?: ExtensionDisabledReason
/** The type of this extension. Will always return 'extension'. */
type: ExtensionType
/** The URL of the homepage of this extension. */
homepageUrl?: string
/** The update URL of this extension. */
updateUrl?: string
/** The url for the item's options page, if it has one. */
optionsUrl: string
/**
* A list of icon information. Note that this just reflects what was declared in the manifest, and the actual
* image at that url may be larger or smaller than what was declared, so you might consider using explicit
* width and height attributes on img tags referencing these images. See the manifest documentation on icons
* for more details.
*/
icons?: IconInfo[]
/** Returns a list of API based permissions. */
permissions?: string[]
/** Returns a list of host based permissions. */
hostPermissions?: string[]
/** How the extension was installed. */
installType: ExtensionInstallType
}
/* management functions */
/** Returns a list of information about installed extensions. */
function getAll(): Promise<IExtensionInfo[] | undefined>
/* management events */
/** Fired when an addon has been disabled. */
const onDisabled: WebExtEvent<(info: IExtensionInfo) => void>
/** Fired when an addon has been enabled. */
const onEnabled: WebExtEvent<(info: IExtensionInfo) => void>
/** Fired when an addon has been installed. */
const onInstalled: WebExtEvent<(info: IExtensionInfo) => void>
/** Fired when an addon has been uninstalled. */
const onUninstalled: WebExtEvent<(info: IExtensionInfo) => void>
}
// html-tagged-template.js
declare function html(

View file

@ -14,7 +14,7 @@
"noImplicitThis": true,
"strictFunctionTypes": true,
"baseUrl": "src/",
"types": ["@types/firefox-webext-browser", "web-ext-types"],
"types": ["@types/firefox-webext-browser"],
"paths": {
"@src/*": ["*"]
}

View file

@ -2652,10 +2652,10 @@ eslint-plugin-import@^2.22.1:
resolve "^1.17.0"
tsconfig-paths "^3.9.0"
eslint-plugin-jsdoc@^32.3.3:
version "32.3.3"
resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-32.3.3.tgz#c430f5d289b6251cb1bf49585858b2335890dab3"
integrity sha512-WxXohbMYlZvCt3r7MepwT++nTLsO4CPegWcm5toM4IGq3MBmYkG+Uf5yDa+n1MwPXLg+KbJqAsI19hmkVD7MPg==
eslint-plugin-jsdoc@^32.3.4:
version "32.3.4"
resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-32.3.4.tgz#6888f3b2dbb9f73fb551458c639a4e8c84fe9ddc"
integrity sha512-xSWfsYvffXnN0OkwLnB7MoDDDDjqcp46W7YlY1j7JyfAQBQ+WnGCfLov3gVNZjUGtK9Otj8mEhTZTqJu4QtIGA==
dependencies:
comment-parser "1.1.5"
debug "^4.3.1"
@ -7503,11 +7503,6 @@ wcwidth@^1.0.0:
dependencies:
defaults "^1.0.3"
web-ext-types@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/web-ext-types/-/web-ext-types-3.2.1.tgz#3edc0e3c2e8fe121d7d7e4ca0b7ee0c883cea832"
integrity sha512-oQZYDU3W8X867h8Jmt3129kRVKklz70db40Y6OzoTTuzOJpF/dB2KULJUf0txVPyUUXuyzV8GmT3nVvRHoG+Ew==
web-ext@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/web-ext/-/web-ext-6.0.0.tgz#0da07ab1b88aa450374fea43c793114c42348d41"