zyedidia/micro

Auto completion

jannisch opened this issue ยท 43 comments

Because micro already provides features like true color support, I wonder why there is not even an automatic completition for brackets and statements like def in python in ruby.
Is this feature not implemented yet or do I experience a bug? Unfortunately I can't code in go.

Thanks!

Unfortunately this feature is not implemented yet, although I plan to do it at some point. I think auto closing brackets, quotes, parentheses etc... is different from autocompletion for actual code keywords (and far easier to implement so that will probably get done first).

I think it would be best to have an autocompletion core in micro, and implement specific completion for each language in plugins. Micro can't magically know that def is a Python statement, and instead can use a code completion engine built for Python, such as Jedi. Of course, not all languages have something like Jedi to do auto completion, so in that case micro can just fall back to simple buffer completion (where it will auto complete any word that is already used in the current file).

Anyway, I'll try to implement auto complete for brackets soon, and I'll do more advanced auto completion some time in the future, but that's a lot more complex.

I totally agree, the benefit of code keywords and whole API catalogs is also smaller.

But let me explain the following example for a method definition in ruby:

def mymethod(myparam)
  # some action
end

If the user types in an usual bracket, a closed one will be added after the cursor. In the above example, \n \nend would do the same trick after the user types def. This can also be limited to ruby because micro already recognizes the language as I saw.
So the most important language features might still be in the scope, we just need a few contributers to collect those patterns.

I appreciate your effort.

IMO it would be best if something like this get handled very similar to how syntax highlighting is done. So just simple files with regex patterns, and some pre-defined actions, like "Add X character(s) on the next line" or "Add X character(s) after the cursor".

Yeah, I think what you're looking for here is snippets, and luckily, Vim users have already collected all those patterns. We just need a way of reading the snippet files and then of course actually implementing the snippet functionality. See here for lots of snippets that are already made. Those files are for the Vim plugin snipmate, but there are more complex ones in that repository for the Vim plugin UltiSnips. Those snippets are more complex but also more powerful, so we'll have to decide which one to use.

Anyway, I think this is a separate issue from snippets, although maybe snippets is what you meant originally. In any case, I think autocomplete and snippets are both features that would be great to have in micro and will hopefully get implemented at some point soon.

Thanks for the new autoclose feature, it works very well.

The vim snippets look quite hard to read/parse, for example this one:

class ${1:`substitute(vim_snippets#Filename(), '\(_\|^\)\(.\)', '\u\2', 'g')`}
        ${0}
end

They also seem to cover many languages completely which I simply did not want to request here, originally I just thought of brackets and the most basic snippets.
But of course I'd be very happy about a very powerful snippet completition in the future, you can close this issue of course if you want to.

Just as a reference for autocomplete function implemented in vim, there's one utilizing lua that is also popular: https://github.com/shougo/neocomplete.vim (I recall saw this or something similar before, using lua for auto-completion functionality in vim).

It would be great if there was autocompletion not only for languages, but also for commands available - would make Micro even more intuitive as you'd discover commands by typing them!

There is in fact autocompletion for commands. Maybe I should say that somewhere in the docs though... Just press tab and it should give you a list of suggestions in the statusline. It will also autocomplete filenames, and options when appropriate.

Aah. I guess I was expecting autocompletion like the one fish does. It will show the first autocompletion match as faded colors like this:

And then you can "scroll" up and down with the arrow keys to see different matches. To accept the suggestion you can press right arrow - pretty intuitive.

As for VS Code - it uses an open JSON-based Language Server Protocol for things like syntax highlighting and code completion. I don't know how hard would it be to implement support for this protocol in micro, but IMO it's a very promising solution:
https://code.visualstudio.com/blogs/2016/06/27/common-language-protocol

I really like the idea of this standart, but the list of implementations is very limited and it is "immature", e.g. the server for rust:

This project is in the early stages of development, it is not yet ready for real use. It will probably eat your laundry.

jantb commented

This box can be used to auto completion once it is exposed to plugins. There is a mode without the prompt that just shows the list.

later in December I would like to try implementing Language Server Protocol (client) to micro. Golang has most of the primitives implemented already, so the communication part should be easy. I am wondering if this kind of improvement would be considered welcome. If so, can somebody provide clues how it would be suitable to be implemented?

sum01 commented

@askalski Maybe https://github.com/Alloyed/lua-lsp could be used in some way

@sum01 thank you. From what I understand is that I need to implement LSP client and languages provide servers. Also, I think I will dive into editing micro with go-lang to implement client. But I am still learning language features.

a-h commented

I put together a quick hack using gocode and a Lua plugin.

To run it, create the file ~/.config/micro/plugins/gocode_ac/gocode_ac.lua

function gocode(offset)
    --TODO: Work out how to get the current buffer contents and pass it to gocode via stdin instead
    -- of saving and using the -in parameter. For large files, this is likely to be inefficient, perhaps
    -- micro keeps a scratch temporary file?
    CurView():Save(false)
    -- Use gocode and output the results of the autocomplete in JSON.
    local handle = io.popen("gocode -f=json -in=" .. CurView().Buf.Path .. " autocomplete " .. offset)
    local result = handle:read("*a")
    --TODO: Work out how to parse the JSON (or text output) and create a list of options to return.
    messenger:AddLog("gocode result: " .. result)
    handle:close()
end

function onRune(r, v)
    --TODO: Add some logic to determine when to start autocompleting. This will be:
    -- * When a period is entered (e.g. "fmt." should produce "fmt.Println")
    -- * When a bracket is opened (e.g. "fmt.Println(" should give information about the parameters)
    -- * When Ctrl+Space is pressed

    --TODO: Add some logic to determine when to stop autocompleting, e.g.
    -- * Escape is pressed
    -- * A selection is made from the list and entered into the buffer
    -- * The bracket is closed
    -- * Space is pressed

    -- Convert the position of the cursor to a byte offset for use with gocode.

    -- The '-' here is to derefence the pointer to v.Cursor.Loc which is automatically made
    -- when converting go structs to lua
    local offset = ByteOffset(-v.Cursor.Loc, CurView().Buf)
    messenger:AddLog("rune: " .. r .. offset)

    gocode(offset)

    return false
end

Open up the editor again, and switch on logging by hitting Ctrl+E and then typing log.

Start editing the text...

At that point, every time you hit a rune in the editor, the onRune function will be hit. It's then possible to use the ByteOffset function to grab the offset, and pass it to the gocode command line tool.

It's very crude, but it shows that the autocomplete function is possible. The log shows r: .200 which means . was pressed at byte offset 200 and the JSON returned from gocode is what I'd expect to see.

screen shot 2017-12-30 at 14 53 55

So... any pointers on how to draw out a list of options, or does someone want to give that a blast?

a-h commented

Apologies for the Go-specific nature of the above. I appreciate that it's not a globally useful solution.

If the approach is to tackle this via a language server integration, then I guess it doesn't need to be a plugin and could be added to the core (and therefore written in Go)?

a-h commented

I've started up on the autocomplete functionality as part of the core of micro in Go instead of as a plugin. I spent a few hours and I think what I've done would be a reasonable way to be able to extend it to other languages over at https://github.com/a-h/micro

It doesn't insert text into the buffer yet, that's next.

autocomplete_show_options

Look about right?

a-h commented

Just added ability to select an option. For functions, it doesn't yet list the parameters, just everything you could write.

select_option

sum01 commented

I like it, simple and efficient. Hopefully you made sure to expose the proper functions so plugins can easily add onto it.

a-h commented

Great, if I'm headed in the right direction, I'll keep on going. Good point on the plugin support, I'll make sure it's possible to write a plugin that can use autocomplete functionality. (adding options to, triggering and hiding the "dialog").

a-h commented

Created pull request: #977

Definitive +1 for a general Language Server Protocol implementation. The project got a new website recently, with this page listing all the supported languages (that includes Go).

Looks like a quick win...

Simple buffer autocompletion (based on words in the current buffer) is now supported. The framework for autocompletion is also implemented so hopefully soon we can have support for more complex autocompletion and a plugin interface.

It's amazing to see how Micro is growing sometimes slowly but steady. Have been waiting for buffer auto-completion for so long. Great job everyone involved, keep going.

Are there any status updates? Just curious.

I'd love to be able to provide additional autocomplete support via a plugin.
Use-Case: I'd love to be able to provide a list of additional words that are auto-completed, for example when writing emails with my ${EDITOR} I'd like to auto-complete email-addresses.

Is there a starting point for this yet where I can pick up?

Would love to use micro as my daily-driver text editor, will this feature be added?

szw commented

@zyedidia Is there a way to customize the word boundaries in the simple buffer autocompletion based on the filetype? I can't make it to work for so-called lispy identifiers (Lisp/Clojure/Scheme use dashes in identifiers-, the same way as underscores everywhere else).

we need a tabnine port for micro.

Thanks for the suggestion, tabnine looks like it could be a good as a solution to more advanced autocompletion than what currently exists in micro.

@zyedidia How do you use the built-in buffer autocompletion? Is it supposed to popup by itself, or do I have to use some keybinding? It turns out you just press TAB and you get a completion.

I am also a big fan of the LSP implementation and would love to see if someone has started working on this, as I might be able to help.

wow i love this

Hello, how are you โœ‹
Do you still have the plan to implement go autocomplete natively on the micro?
I had a look at the gocode but I couldn't find the settings for the micro.
I love this editor. โค๏ธ

any updates? will native autocomplete be implemented?

I'm just waiting for this LSP feature to definitively leave NeoVIM+CoC. ๐Ÿ™‚

I put together a quick hack using gocode and a Lua plugin.

To run it, create the file ~/.config/micro/plugins/gocode_ac/gocode_ac.lua

function gocode(offset)
    --TODO: Work out how to get the current buffer contents and pass it to gocode via stdin instead
    -- of saving and using the -in parameter. For large files, this is likely to be inefficient, perhaps
    -- micro keeps a scratch temporary file?
    CurView():Save(false)
    -- Use gocode and output the results of the autocomplete in JSON.
    local handle = io.popen("gocode -f=json -in=" .. CurView().Buf.Path .. " autocomplete " .. offset)
    local result = handle:read("*a")
    --TODO: Work out how to parse the JSON (or text output) and create a list of options to return.
    messenger:AddLog("gocode result: " .. result)
    handle:close()
end

function onRune(r, v)
    --TODO: Add some logic to determine when to start autocompleting. This will be:
    -- * When a period is entered (e.g. "fmt." should produce "fmt.Println")
    -- * When a bracket is opened (e.g. "fmt.Println(" should give information about the parameters)
    -- * When Ctrl+Space is pressed

    --TODO: Add some logic to determine when to stop autocompleting, e.g.
    -- * Escape is pressed
    -- * A selection is made from the list and entered into the buffer
    -- * The bracket is closed
    -- * Space is pressed

    -- Convert the position of the cursor to a byte offset for use with gocode.

    -- The '-' here is to derefence the pointer to v.Cursor.Loc which is automatically made
    -- when converting go structs to lua
    local offset = ByteOffset(-v.Cursor.Loc, CurView().Buf)
    messenger:AddLog("rune: " .. r .. offset)

    gocode(offset)

    return false
end

Open up the editor again, and switch on logging by hitting Ctrl+E and then typing log.

Start editing the text...

At that point, every time you hit a rune in the editor, the onRune function will be hit. It's then possible to use the ByteOffset function to grab the offset, and pass it to the gocode command line tool.

It's very crude, but it shows that the autocomplete function is possible. The log shows r: .200 which means . was pressed at byte offset 200 and the JSON returned from gocode is what I'd expect to see.

screen shot 2017-12-30 at 14 53 55

So... any pointers on how to draw out a list of options, or does someone want to give that a blast?

so um whered the damn thing go!

Any progress on this? (Or a plugin that intergrates Jedi with Micro?)

@XxnittanixX , nice to see you playing with high quality completion. I tried similar approach to LSP, executing gopls binary to get function signatures. However, @AndCake has now created a real JSON-RPC LSP plugin. As it keeps the language server running and communicates trough RPC, it's likely more efficient. It has some rudimentary support for LSP auto completion. Micro's LSP support and the plugin are also discussed in #1138.

If you want to try it out, it's a two line install. E.g. on Debian 'sudo apt-get update; sudo apt-get -y install micro golang-go gopls; micro --plugin install lsp'. To test it, write a hello world 'micro hello.go', move cursor over PrintLn and press alt-K. Auto completion is ctrl-space.

Update: Go installation is the easiest. Python installation is detailed in help/lsp.md. It has also been briefly tested with Javascript, Typescript, Rust and Lua; installation instructions for these would be nice.

This looks amazing, thanks @AndCake

micro_lsp

Sorry to bump this, but I'm having a hard time recreating the behavior shown here

This looks amazing, thanks @AndCake

micro_lsp micro_lsp

I ran

micro -plugin install lsp
pip install "python-lsp-server[rope,ruff,pylsp-mypy]"
pip install pylsp-mypy

Then set my ~/.config/micro/settings.json to

{
	"lsp.server": "python=pylsp",
	"lsp.formatOnSave": true,
	"lsp.tabcompletion": true,
	"lsp.autocompleteDetails": false
}

which, for some reason, after quitting micro automatically gets rewritten to

{
	"lsp.server": "python=pylsp"
}

After this, none of the commands (ctrl+space, alt+k, alt+r, alt+d) do anything. I was hoping someone could point me in the right direction? Is there something I forgot to configure or some docs that I missed on accident?

Edit: Okay maybe it's not that nothing's happening, but it's incredibly delayed? I smashed ctrl+space over and over again and eventually something did show up, but

  1. the completions don't seem to be for what precedes (i.e. ctrl+space after gc. shows ArithmeticError, AssertionError, etc. instead of say collect)
  2. trying to ctrl+space after gc.colle just wipes out the .colle instead of autocompleting, which I assumed was possible as shown here

@ryan-caesar-ramos micro-plugin-lsp is a 3rd party plugin so a better place for the discussion would be its own repository (I wouldn't expect much as the project is not very active though).

In my experience the autocompletion feature in micro-plugin-lsp is too buggy to be usable. I wrote my own alternative LSP plugin a while back, it's also far from perfect but its autocompletion has worked better for me most of the time.

@Andriamanitra Thank you for the tip! Also appreciate you linking your alternative, I'll take a look