8000 User define completions by GHolk · Pull Request #5404 · tridactyl/tridactyl · GitHub
[go: up one dir, main page]

Skip to content

User define completions - #5404

Draft
GHolk wants to merge 13 commits into
tridactyl:masterfrom
GHolk:user-completion
Draft

GHolk wants to merge 13 commits into
tridactyl:masterfrom
GHolk:user-completion

Conversation

@GHolk
@GHolk GHolk commented Jun 17, 2026
Copy link
Copy Markdown
Contributor

Similar syntax as jsurls.

How ever I found a problem that javascript code in commandline_frame.ts
can not access webpage's dom. This make usercompletions very limited.

I found that src/completions/Goto.ts use message call to retrieve dom content.
Maybe I should do so for usercompletions.

This revision will not pass the linter and typescript's type checker.

GHolk added 4 commits May 20, 2026 23:08
The mergeDeepCull set a unbind key (null) to undefined.
In getURL, there are multiple merge operations,
and undefined is ignored in the following merge.
@GHolk
GHolk commented Jun 17, 2026 •
Copy link
Copy Markdown
Contributor Author

Uhm, some old commits show up here 🤔

Syntax example:

set usercompletions.foo (argv,ctx)=>{
    if (!ctx.comp) ctx.comp= [
        'arg1',
        ['option2', 'display text 2']
    ];
    return ctx.comp
}

usage:

    set usercompletions.foo (argv,ctx)=>{
        if ((Date.now() - ctx.last) > (60 * 1000)) {
            ctx.comp = null
        }
        if (ctx.comp) return
        ctx.comp = [
            'arg1', ['option2', 'display text 2']
        ]
        ctx.last = Date.now()
        return ctx.comp
    }
@bovine3dom
Copy link
Copy Markdown
Member

I found that src/completions/Goto.ts use message call to retrieve dom content.

i think in theory the tabsProxy should make that a bit easier, but I haven't used it for a while so I can't remember how it works

Comment thread src/lib/config.ts
@@ -738,6 +738,8 @@ export class default_config {
prev: "^(prev(ious)?|older)\\b|«|<<",
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please don't forget to give this a good docstring :) . we should bikeshed the name a bit, we try to use vim-style pseudonamespacing where the category comes first

so completionscustom e.g.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am fine to follow vim-style naming convension :)
Juse remember to hint me because I dont use vim directly. I use emacs evil ;)

@Chic-Tweetz
Copy link
Copy Markdown
Contributor

How ever I found a problem that javascript code in commandline_frame.ts can not access webpage's dom. This make usercompletions very limited.

I had a crack at this (apparently 5 months ago 😮) and added a completions_content.ts to handle the messaging between the iframe and the page.

The main idea was to message with the prefix and reply with the options (and anything else from the config), that's response in get_custom_completion. Don't know if it'll be helpful at all, but take inspiration from that if you like

I believe most use case for completion is dealing with page content
@GHolk
GHolk force-pushed the user-completion branch from 350e31a to 71bb3b0 Compare June 20, 2026 13:38
@GHolk
GHolk commented Jun 20, 2026 •
Copy link
Copy Markdown
Contributor Author

I move the completion generation into content-script,
because I believe most case user want to generate completion from page content.

Moreover, I'm rethinking the API.
Current API is just a wrapper around the existing completion API,
which is not very suit to my imaginary use case.

My first use case is to choose drop-down menu with completion api.

  1. hint -c selection -F e=>{ var value = [], display = []; /* some code */; tri.excmds.completionsetup('--fuse=true -q #', e.id, '--complete', value.concat(display).join(' '))}
  2. the excmd open cmdline, and show menu item as completion
  3. user can select item in ex mode.

I want to design a elegant API that be able to handle this task.
Im wondering whether we should design a hint -F like api
or make completion selection execute a normal ex command.

approach 1

code example:

# execute this
completionsetup -F value=>$('#'+tri.compid).value=value -v value1 -p preview%20one -v value2 ...

# fillcmdline with this generate following completion
completionfill -F value=>$('#'+tri.compid).value=value
# preview one
# preview tow
# ...

In this case, user have to pass context object in other way,
because completionfill only recognize string arguments.

approach 2

Or make the completionfill a special non-idempotent command,
that can not execute directly, but can only be triggered with completionsetup command,
and its behavior is dependent on the setup command.


I'm busy with dragon boat festival this weekend,
so previous commit is not test at all.
I may not have time to work on this this weekend.

@GHolk
GHolk commented Jun 20, 2026
Copy link
Copy Markdown
Contributor Author

I had a crack at this (apparently 5 months ago 😮) and added a completions_content.ts to handle the messaging between the iframe and the page.

It is a very comprehensive implementation!
Will you work on it?

@GHolk
GHolk commented Jun 21, 2026 •
Copy link
Copy Markdown
Contributor Author

proposal, completionsetup and comp commands.
Shortly, I want to add a fzf like interface.

javascript api

completionsetup will return a object
containing a promise field which resolved with the user input.

easy example

// fillcmdline with `comp -n `
const exec = tri.excmds.completionsetup({
    action: null,
    data: 'youtube.com google.com'.split(' '),
    preview: ['YouTube', 'Google Inc']
})
// user choose *YouTube*, the exstr become `comp -n youtube.com `
const d = await exec.promise
// user press Enter, the promise resolve with 'youtube.com'
tabopen(d)

drop-down menu example

command drop-down-menu-prompt hint -c select -F async e=>{
    const data=[], preview=[]
    for (const opt of e.options) {
        data.push(o.value)
        preview.push(o.textContent)
    }
    const exec = tri.excmds.completionsetup({
        action: null,
        data, preview
    })
    const v = await exec.promise
    e.value = v
}

excmd style api

this command will open cmdline with 2 completion option.

  • -d: real value to insert when user select a completion
  • -p: preview, optional
  • -x: the exstr to execute
  • -F: the js callback function to execute
  • -n: do not execute everything, just resolve the promise with value
completionsetup -x tabopen -d youtube.com -p YouTube -d google.com -p Google%20Inc

the cmdline will fill with following exstr and 2 completions

comp -x tabopen
# YouTube
# Google Inc

after user select Google Inc and call ex.insert_completion

comp -x tabopen google.com

the comp command will simply execute the -x option
so the previous command is same to

tabopen google.com

the -x -F -n options here are same to the completionsetup options

@Chic-Tweetz
Copy link
Copy Markdown
Contributor

It is a very comprehensive implementation! Will you work on it?

I have been meaning to. It's funny though because since I've had it working I haven't actually used it 😄 so I have neglected it a bit.

I was planning on reimplementing existing completions in a way that would let them be easily reused for custom completions, but that feels like it'll take a bit of effort so I never started :)

GHolk added 6 commits June 23, 2026 23:53
usage:

completionsetup -x help -d set -d get -d help
completionsetup -x tabopen -d %2Dc%20foo%20google.com -d google.com
js completionsetup({value: 'a b c'.split(' '), callback(x) {alert(x)}})
js completionsetup({value: 'a b c'.split(' ')}).then(async o => {const choose = await o.promise; alert(choose)})
* completionscustom callback: allow set option.callback
* completionsetup -j: function takes full controll of completion
@GHolk
GHolk commented Jun 26, 2026
Copy link
Copy Markdown
Contributor Author

Fine, the feature is finished now. We just need to type them correctly and refactor.

To build, use the npm run rebuild command which will accept all un-typed code.

discuss

As getGotoSelectors , I put them in excmds.ts initially,
should I move the non-excmd code to contents/completion_custom.ts or somewhere?

Chic's branch makes use of commandline_content message type.
Should I use it too?

Now there are two features, completionsetup and completionscustom.* .
They interlace in content script (excmd) and background script (CompletionsCustom.ts) .
I think it is possible to split the background part.
Should I do that?

I am also thinking about adding a callback style completion interface inside Tridactyl.
Should I add it in this PR?

@bovine3dom @Chic-Tweetz how do you think?

do not provide origin command's completion if
there has a custom completion.

for example:

```
alias openfavorite open
set completionscustom.openfavorite ()=>'youtube.com google.com'.split(' ')
```
@bovine3dom bovine3dom self-assigned this Jun 28, 2026
@bovine3dom
Copy link
Copy Markdown 8BD0
Member

this looks good as a stop-gap before we do #105 (lol)

i'm trying to get my head around :comp

is the idea that it is used for 'temporary' completions via :completionsetup and permanent ones are set via :set completionscustom.foo which then would provide completions for :foo ?

@Chic-Tweetz
Copy link
Copy Markdown
Contributor

I do like the :completionsetup idea, I imagine it'd be best used in conjunction with :js if you wanted to populate it with more than a few choices?

I haven't figured out how to get completionscustom to actually display using the mygoto example (I was expecting options to display if I type :mygoto - is that right?)

I am also thinking about adding a callback style completion interface inside Tridactyl. Should I add it in this PR?

If this is similar to the callback stuff I made, I'd like to add the juicy detail that a callback that triggers as you type into the command line is how I got incsearch working :) ... another thing I should get back to!

@GHolk
GHolk commented Jul 6, 2026 •
Copy link
Copy Markdown
Contributor Author

I have some examples in js-doc, completionscustom in lib/config.ts
and completionsetup in excmds.ts .

@bovine3dom Does it still worth today?

comp is a placeholder command. For example,
after completionsetup , we can not fillcmdline with tabopen
or it will trigger tabopen's completion, so I use comp -x tabopen .

comp do two things:

  1. execute the excmd of -x option or js code of -F option
  2. Trigger the callback (-n) defined in the completionsetup({callback}) and clear it

There is no magic in the first situation,
so you can summon it from the cmdHistory and execute it again.

In second situation, it will not work unless we execute
completionsetup({callback}) again before it.


About completionscustom.foo , there have to be a foo command.

One can define foo as an alias of tabopen or other excmd,
(alias will trigger origin command's completion before the fix in 1ca9c41)
or as an alias of comp -x tabopen , or any js command.

Another way, one can define the callback by set option.callback
(in the set completionscustom.foo (argv,ctx,option) => { option.callback = ... } )
and make foo as an alias to comp -n .

The callback style magically keep the closure context; we sometimes need this.

The first -x|-F has no magic and has no closure context too.


@Chic-Tweetz Right, completionscustom.mygoto work as you wrote.

I may not add many details about the data-structure of completion.
The callback style completion API is to let developer
define completions like completionscustom.* is tridactyl's source code,
because the current CompletionSource API is a little verbose to me.

@bovine3dom
Copy link
Copy Markdown
Member

hey @GHolk every few days i look at this and then realise it's really complicated and ... find something else that's easier to work on 😅

could you summarise 1) things you would like me to help you decide and 2) things i should copy and paste into the command line to test?

ideally in simple words that my caveman brain can understand

sorry and thank you ❤️

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

0