Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider creating an option to mimic previous tab behavior #193

Open
non-Jedi opened this issue May 12, 2023 · 18 comments · Fixed by #196
Open

Consider creating an option to mimic previous tab behavior #193

non-Jedi opened this issue May 12, 2023 · 18 comments · Fixed by #196

Comments

@non-Jedi
Copy link
Contributor

Per @ronisbr, #185 significantly change the behavior of TAB.

#188 (comment):

If I use the latest commit with (setq julia-force-tab-complete t) (default), I can replace LaTeX symbols by pressing TAB. For example, "\alpha<TAB>" gives α. However, in this case, TAB always force indentation update. Hence, I am not able, for example, to increase the indentation by pressing TAB repeatedly as I could before.

If I set (setq julia-force-tab-complete nil), now I can increase the indentation by pressing TAB repeatedly. However, I lost the ability to replace LaTeX symbol by hitting TAB. In this case, I must use C-SPC, which is my default completion keystroke.

I am not saying we must revert to the old behavior. I am just saying that the behavior has changed and I am not certain if this is a bug or how the new system must work.

To me, this brings TAB behavior back in line with how users of the rest of emacs would expect it to behave, and I see it as a benefit. If there's sufficient interest, I could create a configuration option that would cause TAB to simulate the old behavior.

@ronisbr
Copy link
Contributor

ronisbr commented May 12, 2023

I really prefer the old behavior because it is consistent with REPL. If you hit TAB after a LaTeX symbol, it replaces it, and if you hit TAB at the beginning of the line, it increase indentation. It is much easier (at least in my setup) to format docstrings.

@tpapp
Copy link
Collaborator

tpapp commented May 13, 2023

@ronisbr: We can bring it back, and with the hash table lookup it should be easy, but let's focus on the details first.

In the examples below, | is the point.

  1. \prefix|noise matches multiple ones, eg \prefix1, \prefix2, etc. Here noise is irrelevant. What should it do, pick the first one, offer a list with a popup, or something else?
  2. \pre|fixnoise matches \pre and \prefix, what should it expand to?

Note that the REPL behavior is the following on 1.9:

  1. on \al|eph, it refuses to replace, just throws up \alpha, \allequal, and \aleph.
  2. on \al|noise, same thing.
  3. \not| will just expand greedily, and not offer \notin.
  4. \not|in will expand to ̸in, again greedily.

I think that the REPL is made for interactively entering text and expanding on whatever comes before the point. It is very rare (I think) to go back in the REPL prompt and expand text. Whereas in an editor there is text before and after the point.

I kind of missed the REPL behavior for a while, so I understand the issue, but in the end I arrived at the conclusion that editors need different semantics. I am very happy with the current setup now, as we get expansion within the symbol a way to resolve multiple options.

That said, I am open to a mechanism that mimics the REPL in some way. Just please spend some time thinking about the semantics.

@ronisbr
Copy link
Contributor

ronisbr commented May 15, 2023

Perfect @tpapp !

Maybe we should not really replicate the entire REPL behavior. Is there any technical problem to always call auto-completion if a symbol does not resolve to a single solution? So, in all those cases, it would open that popup if I hit TAB?

What I really miss is the ability to use TAB to increase indentation if we does not have a LaTeX symbol. For example, if I hit TAB here:

A = [1| 2

I would like to go to here:

A = [1   | 2

instead of indenting the current line.

@dhanak
Copy link
Contributor

dhanak commented May 18, 2023

(copied from a comment on #185)

Hello!

I have set up my Emacs to upgrade my (m)elpa packages automatically on a weekly basis. Thus, it came as a surprise to me that tab completion substitution for LaTeX symbols in julia-mode broke some time earlier this week. Then it took me a while to investigate the issue and track the root cause down to #185.

Granted, I have ivy-mode installed, and I noticed the comments in the source code related to abo-abo/swiper#2345. But that seems like an old issue, yet julia-mode worked perfectly until recently. Furthermore, there is nothing wrong with the substitution of LaTeX symbols which are unambiguous, e.g., \circeq, only those which have multiple possible suffixes, e.g., \circ and \in.

Moreover, when I type \circ<TAB> 99.99% of the time I want it to be substituted with the circle symbol, and not to be completed to some hardly ever used LaTeX symbol name that also happens to begin with \circ. The same goes for \in.

I spent the better part of an hour trying to figure out how to patch the change to bring the old behavior back, to no avail. I finally gave up and went back to the January 19 version of julia-mode which I restored from a snapshot.

Note that I don't really want to start using abbrev. As I switch back-and-forth between Emacs and REPL, I definitely want to use the same key to expand symbols, otherwise I'm sure to mess it up regularly.

I think this will be an issue for others as well, so I'd like to offer my help to come up with a solution that suits (almost) everybody.

@tpapp
Copy link
Collaborator

tpapp commented May 18, 2023

@dhanak: please read the discussion above. TL;DR: the key question is defining the semantics, after that we can implement it.

@dhanak
Copy link
Contributor

dhanak commented May 18, 2023

I think I would prefer simple prefix completion, offering choices if there are several. In the case of your examples:

  1. offer a list;
  2. expand to \pre and substitute.

I don't think I have ever pressed tab in the middle of a word and expected the editor to take the suffix into account as well. When I do press tab in the middle of a word, it happens because it is not really a word, I just went back and started to enter something before what was already there. So I'd prefer the editor to leave that part as is. With a somewhat forced example:

  • input: eq| -> |eq -> not \circ|eq, <TAB>, <SPACE>
  • I expect: not ∘ eq
  • I wouldn't like to see: not ≗

(As for the indentation, I have no issues with it.)

@non-Jedi
Copy link
Contributor Author

non-Jedi commented May 18, 2023

Sounds like we actually have two separate desires here:

  1. Allow tab-completion of LaTeX symbols while preserving indentation behavior of (setq tab-always-indent nil)
  2. Greedily substitute on exact prefix match: Don't prompt when completing \circ to offer choice of \circeq; just directly complete to .
  • As noted above, this should not apply to middle-of-symbol completion, and perhaps middle-of-symbol completion should be entirely disabled when in this mode.

Path forward I see is to have a julia-indent-for-tab-command function and a customization variable for each of the points above. julia-indent-for-tab-command would just check the values of each of the customization variables, set tab-always-indent and completion-at-point-functions to appropriate values, and then explicitly call some combination of expand-abbrev, indent-for-tab-command, and completion-at-point depending on values of customization.

@tpapp
Copy link
Collaborator

tpapp commented May 18, 2023

What we could do the following:

On \pre|post

  1. if pre matches a substitution exactly, replace,
  2. if not, flash choices in the Messages buffer, or popup, or say that there is absolutely no match

Otherwise, if there is no \ in the line before the point, try indenting.

@dhanak, @ronisbr, would this match your use case?

@ronisbr
Copy link
Contributor

ronisbr commented May 18, 2023

Hi @tpapp !

@dhanak, @ronisbr, would this match your use case?

If you mean that try indenting is calling (indent-for-tab-command arg), then yes, it will match!

@dhanak
Copy link
Contributor

dhanak commented May 18, 2023

@dhanak, @ronisbr, would this match your use case?

Yes, that sounds good to me.

@tpapp
Copy link
Collaborator

tpapp commented Jun 20, 2023

I am working on a solution in #193. Please test, suggestions welcome (including code improvements, UI suggestions, etc).

@giordano
Copy link

giordano commented Nov 7, 2023

Do I understand correctly that at the moment there's no way to get \alph to be automatically completed to \alpha and then replaced with α? I'm asking with or without pressing TAB (which would be taken care of by #196), I don't see any interactive function which can do this operation of completion+substitution at all.

@non-Jedi
Copy link
Contributor Author

non-Jedi commented Jan 25, 2024

Hi @giordano. Sorry I missed your question until now. Invoking completion-at-point (C-M-i in vanilla emacs) in a julia-mode buffer will complete "\alph" directly to "α." I just tested this out using emacs -Q and installing only julia-mode and confirmed this works for me as expected. Are you seeing a situation where this doesn't work?

@giordano
Copy link

Invoking completion-at-point (C-M-i in vanilla emacs), in a julia-mode buffer will complete "\alph" directly to "α." I just tested this out using emacs -Q and installing only julia-mode and confirmed this works for me as expected. Are you seeing a situation where this doesn't work?

Yes, "\alph" for me is completed to "\alpha", not "α", further pressing M-C-i does nothing. Not sure it's relevant, but I use Helm. I also have auto-complete installed, but doesn't seem the mode is active in my julia buffer.

@non-Jedi
Copy link
Contributor Author

I've managed to replicate. Will create a new issue.

@dhanak
Copy link
Contributor

dhanak commented Jan 25, 2024

Eventually, I upgraded to Emacs 29, and julia-ts-mode with tree-sitter. Since that uses a different indentation API, this workaround didn't work for me any more, so I gave in and started to use dabbrev to auto-expand escape sequences. My main concern was that this is different from how the REPL works, and my muscle memory will surely mess it up regularly. So I tweaked the REPL instead, to work like dabbrev does. I added this code to my startup.jl:

atreplinit() do repl
    REPL = Base.REPL_MODULE_REF[]
    LE = REPL.LineEdit
    RC = REPL.REPLCompletions

    # define a new keymap
    my_keymap = Dict()
    push!(repl.options.extra_keymap, my_keymap)

    # auto-replace escaped latex and emoji sequences with their symbol
    # counterparts after a punctuation key, just like Emacs abbrev-mode
    function abbrev_expand(s, data, c)
        buf = LE.buffer(s)
        (pos, buf) = (position(buf), LE.content(buf))
        (comp, r, _) = RC.bslash_completions(buf, thisind(buf, pos))[2]
        if length(comp) == 1 && comp[].bslash[1] != '\\'
            LE.edit_splice!(s, prevind(buf, r.start) => r.stop, comp[].bslash)
            LE.refresh_line(s)
        end
        LE.edit_insert(s, c)
    end

    punct = filter(ispunct, Char(1):Char(127))
    for c in [' '; setdiff(punct, ";?]>")]
        my_keymap[c] = abbrev_expand
    end
end

@tpapp
Copy link
Collaborator

tpapp commented Jan 25, 2024

Just to repeat for everyone looking at this issue: #196 works so you can use it, I just did not merge it because I haven't had time to finish it properly (tests etc).

@non-Jedi
Copy link
Contributor Author

non-Jedi commented May 7, 2024

Reopening because #196 doesn't allow you to use TAB for both LaTeX substitution and inserting "real" TABs (see my comment on the PR). Feel free to close again if I'm misunderstanding (it happens rather frequently), and the PR does enable this.

@non-Jedi non-Jedi reopened this May 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants