diff --git a/CHANGES.md b/CHANGES.md index ff31880a3f..f3ca754ebf 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,12 @@ +unreleased +========== + + + vim plugin + - Added support for search-by-type (#1846) + This is exposed through the existing `:MerlinSearch` command, that + switches between search-by-type and polarity search depending on the + first character of the query. + merlin 5.3 ========== Tue Nov 26 17:30:42 CET 2024 diff --git a/vim/merlin/autoload/merlin.py b/vim/merlin/autoload/merlin.py index 5d79cba9b9..581c0aed51 100644 --- a/vim/merlin/autoload/merlin.py +++ b/vim/merlin/autoload/merlin.py @@ -90,7 +90,7 @@ def vim_value(v): if isinstance(v, int): return str(v) if isinstance(v, str): - return "'%s'" % v.replace("'", "''") + return "'%s'" % v.replace("'", "''").replace("\n", "'.\"\\n\".'") raise Exception("Failed to convert into a vim value: %s" % str(v)) # Format a dictionnary containing integer and string values into a Vim record. @@ -362,27 +362,29 @@ def command_holes(): ######## VIM FRONTEND -def vim_complete_prepare(str): - return re.sub(re_wspaces, " ", str).replace("'", "''").strip() - -def vim_complete_prepare_preserve_newlines(str): - return re.sub(re_spaces_around_nl, "\n", re.sub(re_spaces, " ", str)).replace("'", "''").strip() - +# Turns Merlin's search-by-polarity or complete-prefix entries into a Vim's completion-item list (:h complete-items) def vim_fillentries(entries, vimvar): - prep = vim_complete_prepare - prep_nl = vim_complete_prepare_preserve_newlines + def prep(s): + return re.sub(re_wspaces, " ", s).strip() + def prep_nl(s): + return re.sub(re_spaces_around_nl, "\n", re.sub(re_spaces, " ", s)).strip() for prop in entries: - vim.command("let tmp = {'word':'%s','menu':'%s','info':'%s','kind':'%s'}" % - (prep(prop['name']),prep(prop['desc']),prep_nl(prop['info']),prep(prop['kind'][:1]))) + vim.command("let tmp = " + vim_record({ + "word": prep(prop["name"]), + "menu": prep(prop["desc"]), + "info": prep_nl(prop["info"]), + "kind": prop["kind"][:1] + })) vim.command("call add(%s, tmp)" % vimvar) # Complete def vim_complete_cursor(base, suffix, vimvar): + def prep(str): + return re.sub(re_wspaces, " ", str).replace("'", "''").strip() vim.command("let %s = []" % vimvar) try: completions = command_complete_cursor(base,vim.current.window.cursor) nb_entries = len(completions['entries']) - prep = vim_complete_prepare if completions['context'] and completions['context'][0] == 'application': app = completions['context'][1] if not base or base == suffix: @@ -432,6 +434,19 @@ def vim_polarity_search(query, vimvar): except MerlinExc as e: try_print_error(e) +# search-by-type is introduced in https://github.com/ocaml/merlin/pull/1828 +def vim_search_by_type(query, vimvar): + def completion_item_of_result(e): + return { "word": e["name"], "menu": ": %s" % e["type"] } + vim.command("let %s = []" % vimvar) + try: + l = command("search-by-type", "-query", query, "-position", fmtpos(vim.current.window.cursor)) + for r in l: + item = completion_item_of_result(r) + vim.command("call add(%s, %s)" % (vimvar, vim_record(item))) + except MerlinExc as e: + try_print_error(e) + # Error listing def vim_loclist(vimvar, ignore_warnings): vim.command("let %s = []" % vimvar) diff --git a/vim/merlin/autoload/merlin.vim b/vim/merlin/autoload/merlin.vim index 3d925b9daf..caa3959331 100644 --- a/vim/merlin/autoload/merlin.vim +++ b/vim/merlin/autoload/merlin.vim @@ -284,15 +284,33 @@ function! merlin#PolaritySearch(debug,query) let s:search_result = [] MerlinPy merlin.vim_polarity_search(vim.eval("a:query"), "s:search_result") if a:debug != 1 && s:search_result != [] - call feedkeys("i=merlin#PolarityComplete()\","n") + call feedkeys("i=merlin#SearchComplete()\","n") endif endfunction -function! merlin#PolarityComplete() +function! merlin#SearchComplete() call complete(col('.'), s:search_result) return '' endfunction +function! merlin#SearchByType(debug,query) + let s:search_result = [] + MerlinPy merlin.vim_search_by_type(vim.eval("a:query"), "s:search_result") + if a:debug != 1 && s:search_result != [] + call feedkeys("i=merlin#SearchComplete()\","n") + endif +endfunction + +" Do a polarity search or a search by type depending on the first character of +" the query. +function! merlin#Search(debug, query) + if a:query =~ "^[-+]" + call merlin#PolaritySearch(a:debug, a:query) + else + call merlin#SearchByType(a:debug, a:query) + endif +endfunction + function! s:StopHighlight() if exists('w:enclosing_zone') && w:enclosing_zone != -1 call matchdelete(w:enclosing_zone) @@ -813,8 +831,10 @@ function! merlin#Register() command! -buffer -nargs=0 MerlinGotoDotMerlin call merlin#GotoDotMerlin() command! -buffer -nargs=0 MerlinEchoDotMerlin call merlin#EchoDotMerlin() - """ Polarity search - command! -buffer -complete=customlist,merlin#ExpandTypePrefix -nargs=+ MerlinSearch call merlin#PolaritySearch(0,) + """ Search + command! -buffer -complete=customlist,merlin#ExpandTypePrefix -nargs=+ MerlinSearchPolarity call merlin#PolaritySearch(0,) + command! -buffer -complete=customlist,merlin#ExpandTypePrefix -nargs=+ MerlinSearchType call merlin#SearchByType(0,) + command! -buffer -complete=customlist,merlin#ExpandTypePrefix -nargs=+ MerlinSearch call merlin#Search(0,) """ debug -------------------------------------------------------------------- command! -buffer -nargs=0 MerlinDebugLastCommands MerlinPy merlin.vim_last_commands() diff --git a/vim/merlin/doc/merlin.txt b/vim/merlin/doc/merlin.txt index b1c571d5d7..3d23b100c4 100644 --- a/vim/merlin/doc/merlin.txt +++ b/vim/merlin/doc/merlin.txt @@ -158,6 +158,44 @@ Act either as *:py* or *:py3* depending on the version of python is used by the vim plugin. This is only useful if you want to write custom merlin extensions. +:MerlinSearch *:MerlinSearch* + +Act either as :MerlinSearchPolarity or :MerlinSearchType depending on the first +character of the query. If the query starts with '-' or '+', then +:MerlinSearchPolarity is used, otherwise, :MerlinSearchType is used. + +> + :MerlinSearch -int +string + :MerlinSearch int -> string +< + +:MerlinSearchPolarity *:MerlinSearchPolarity* + +Search for values in the current scope that have a type matching the query. +The results are displayed in a completion menu. + +The query language is simply a list of path identifiers prefixed by `+` or `-`, +e.g. `-int`, `-int +string`, `-Hashtbl.t +int`. + +`-` is interpreted as "consuming" and `+` as "producing": `-int +string` looks +for functions consuming an `int` and producing a `string`. + +> + :MerlinSearchPolarity -int +string +< + +:MerlinSearchType *:MerlinSearchType* + +Works similarly to :MerlinSearchPolarity but uses a different query language. +The results are displayed in a completion menu. + +The query language is a list of type constructors separated by '->'. +Type parameters and functions are allowed: `('a -> bool) -> 'a list -> bool`. + +> + :MerlinSearchType int -> string +< + ============================================================================== OPTIONS *merlin-options*