diff --git a/src/LanguageServer.jl b/src/LanguageServer.jl index b6f56131..eda4a89a 100644 --- a/src/LanguageServer.jl +++ b/src/LanguageServer.jl @@ -34,6 +34,7 @@ include("requests/textdocument.jl") include("requests/features.jl") include("requests/hover.jl") include("requests/completions.jl") +include("requests/completions_latex.jl") include("requests/workspace.jl") include("requests/actions.jl") include("requests/init.jl") diff --git a/src/requests/completions.jl b/src/requests/completions.jl index 85370874..ac8fa0b1 100644 --- a/src/requests/completions.jl +++ b/src/requests/completions.jl @@ -257,14 +257,26 @@ end function collect_completions(x::StaticLint.Scope, spartial, state::CompletionState, inclexported=false, dotcomps=false) if x.names !== nothing possible_names = String[] + possible_unicode_altnames = Tuple{String,String}[] for n in x.names + resize!(possible_names, 0) + resize!(possible_unicode_altnames, 0) + + # name, binding = n[1], n[2] # name and binding + if is_completion_match(n[1], spartial) && n[1] != spartial push!(possible_names, n[1]) end + if (nn = string_macro_altname(n[1]); nn !== nothing) && is_completion_match(nn, spartial) push!(possible_names, nn) end + + if (nn = latex_symbol_altname(n[1]); nn !== nothing) && is_completion_match(nn, spartial) + push!(possible_unicode_altnames, (n[1], nn)) # store unicode and alt name, e.g. (α, alpha) + end + if length(possible_names) > 0 documentation = "" if n[2] isa StaticLint.Binding @@ -275,6 +287,31 @@ function collect_completions(x::StaticLint.Scope, spartial, state::CompletionSta add_completion_item(state, CompletionItem(nn, _completion_kind(n[2]), get_typed_definition(n[2]), MarkupContent(documentation), texteditfor(state, spartial, nn))) end end + + + # If we have a unicode altname, add the completion item + if length(possible_unicode_altnames) > 0 + documentation = "" + if n[2] isa StaticLint.Binding + documentation = get_tooltip(n[2], documentation, state.server) + sanitize_docstring(documentation) + end + for (n_orig, nn) in possible_unicode_altnames + # Define the label text that is shown in the completion list in the editor + # TODO Find out why the typed name (e.g. "alpha") has to be shown in the compltion list instead of just the unicode symbol + label_ext = nn * " (" * n_orig * ")" # e.g. "alpha (α)" + add_completion_item( + state, + CompletionItem( + label_ext, + _completion_kind(n[2]), + get_typed_definition(n[2]), + MarkupContent(documentation), + texteditfor(state, spartial, n[1]) + ) + ) + end + end end end end diff --git a/src/requests/completions_latex.jl b/src/requests/completions_latex.jl new file mode 100644 index 00000000..0c76b12c --- /dev/null +++ b/src/requests/completions_latex.jl @@ -0,0 +1,98 @@ + + +# TODO Complete, only a subset for now +latex_inverse_mappings = Dict{Char,String}( +# Greek + 'Α' => "Alpha", + 'Β' => "Beta", + 'Γ' => "Gamma", + 'Δ' => "Delta", + 'Ε' => "Epsilon", + 'Ζ' => "Zeta", + 'Η' => "Eta", + 'Θ' => "Theta", + 'Ι' => "Iota", + 'Κ' => "Kappa", + 'Λ' => "Lambda", + 'Ξ' => "Xi", + 'Π' => "Pi", + 'Ρ' => "Rho", + 'Σ' => "Sigma", + 'Τ' => "Tau", + 'Υ' => "Upsilon", + 'Φ' => "Phi", + 'Χ' => "Chi", + 'Ψ' => "Psi", + 'Ω' => "Omega", + 'α' => "alpha", + 'β' => "beta", + 'γ' => "gamma", + 'δ' => "delta", + 'ζ' => "zeta", + 'η' => "eta", + 'θ' => "theta", + 'ι' => "iota", + 'κ' => "kappa", + 'λ' => "lambda", + 'μ' => "mu", + 'ν' => "nu", + 'ξ' => "xi", + 'π' => "pi", + 'ρ' => "rho", + 'ς' => "varsigma", + 'σ' => "sigma", + 'τ' => "tau", + 'υ' => "upsilon", + 'φ' => "varphi", + 'χ' => "chi", + 'ψ' => "psi", + 'ω' => "omega", + 'ϑ' => "vartheta", + 'ϕ' => "phi", + 'ϖ' => "varpi", + 'Ϛ' => "Stigma", + 'Ϝ' => "Digamma", + 'ϝ' => "digamma", + 'Ϟ' => "Koppa", + 'Ϡ' => "Sampi", + 'ϰ' => "varkappa", + 'ϱ' => "varrho", + 'ϴ' => "varTheta", + 'ϵ' => "epsilon", + '϶' => "backepsilon", + + # Indices + '₀' => "_0", + '₁' => "_1", + '₂' => "_2", + '₃' => "_3", + '₄' => "_4", + '₅' => "_5", + '₆' => "_6", + '₇' => "_7", + '₈' => "_8", + '₉' => "_9", +) + +""" + latex_symbol_altname(s) + +If the string `s` contains latex unicode symbols, return the string with the symbols replaced by their corresponding latex commands. +If there are no latex symbols in `s`, return `nothing`. +""" +function latex_symbol_altname(s) + + parts = map(eachindex(s)) do i + c = s[i] + if !isascii(c) && c ∈ keys(latex_inverse_mappings) + return latex_inverse_mappings[c] + else + return string(c) # needed for typestability + end + end + + # If the number of codeunits is the same as the number of parts, then there are no latex symbols + ncodeunits(s) === length(parts) && return nothing + + return join(parts) +end diff --git a/test/test_completions.jl b/test/test_completions.jl new file mode 100644 index 00000000..b0bf9725 --- /dev/null +++ b/test/test_completions.jl @@ -0,0 +1,12 @@ +@testitem "Completions" begin + import LanguageServer + + + # Test Unicode Altname completion + s = ["α", "decay_β", "θ₀", "x₀", "y", "z"] + s_exp = ["alpha", "decay_beta", "theta_0", "x_0", nothing, nothing] + for (i, (s, s_exp)) in enumerate(zip(s, s_exp)) + @test LanguageServer.latex_symbol_altname(s) == s_exp + end + +end