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

Conditional indent (\if, \fi, \else) #1078

Closed
mrajner opened this issue Mar 8, 2018 · 16 comments
Closed

Conditional indent (\if, \fi, \else) #1078

mrajner opened this issue Mar 8, 2018 · 16 comments

Comments

@mrajner
Copy link
Contributor

mrajner commented Mar 8, 2018

Indenting of conditional

Currently block between \if and \endif is not indented by default. As it is matter of taste vimtex could support optional indention of that syntax.

Introduction of g:vimtex_indent_delims (c146852) allows to mimic this behaviour with settings like

let g:vimtex_indent_delims = {
    \ 'open' : ['\\if'],
    \ 'close' : ['\\fi'],
\}

However it will give the result

\ifnum=1
    Hello world!
   \else
   Bye world!
\fi

The problem is with single line \else which should have temporary decreased indent (only for that line) and restored immediately. To keep the consistency, flexibility of user choice, I would suggest adding another entry in g:vimtex_indent_delims.

let g:vimtex_indent_delims = {
    \ 'open' : ['\\if'],
    \ 'close' : ['\\fi'],
    \'hanging':['\\else']
\}

So in the same manner one could provide a list of regex for hanging lines.

PS Be aware that it should be also regular expression to give full customization.
Also the example with '\\if' and '\\fi' are very simple ilustration.
Actually this expression should be like
'\(\\newif\)\@<!\\if\(field\|name\)\@!' to avoid indenting commands without ending \fi
like defining \newif\ifmyconditional or \iffieldundef or \ifnameundef from biblatex/biber commands, where action for true and false are just given in arguments without ending \fi.
Also closing should be changed to '\\fi\>' so it want parse for instance \field.
But the correct regex is up to user.

@lervag
Copy link
Owner

lervag commented Mar 16, 2018

I'm not very accustomed to \if type of commands in LaTeX. I would like to have a sort of sane default, e.g. something like:

let g:vimtex_indent_conditionals = {
    \ 'open': '\\if\%(num\|false\)\?\>',
    \ 'else': '\\else'
    \ 'close': '\\fi',
\}

I would suspect it suffices with a single regex here, no need for a list. I'll look into this a little bit now. I think I want to keep this separate from delimiters and use a different option.

lervag added a commit that referenced this issue Mar 16, 2018
@lervag
Copy link
Owner

lervag commented Mar 16, 2018

Ok, first version of this is added. It is probably not perfect. As an example of this, the current version assumes that all conditionals are written linewise, e.g., there are never two clauses on a single line, such as \if...\else. We can probably improve this, but let's start simple.

The first thing is to find a good default setting for the regexes.

@mrajner
Copy link
Contributor Author

mrajner commented Mar 16, 2018

Good job. I agree that simple regex should suffice (until one encounter very specific case, which I do not foresee now).
Everything works well with your test case. However I would change the initial value for open,
yours inclusive list

'open': '\v\\if%(num|false)?>'

allows only \if, \ifnum and \iffalse (why not \iftrue also?). But inclusive list is impossible to define.
You can define any conditional name with syntax as below

\newif\ifenglish % define new conditional

\ifenglish
  \usepackage[english]{babel}
\else
  \usepackage[polish]{babel}
\fi

So the list of possible \if... is open. I set just opening regex to

'open' : '\(\\newif\)\@<!\\if\(field\|name\|numequal\)\@!'

so it will properly indent this example with \ifenglish but will not start on defining \newif, and there are few \if starting word which I already figured out to be not closed by \fi.
You could leave your defaults, as this is customizable, and one can always adapt it for his needs. But if you would like to support also users without knowledge of regexps, you may want to use more sophisticated initial setting (I will of course notify you if I found other exceptions).
The else and close dictionary entries seems to be fine. Some very localized situation could require change it a little (package algorithmicx adds among others \EndIf and \Elsif). But this is very localized problem.

PS If I try to set only one dictionary entry

let g:vimtex_indent_conditionals = {
 \ 'open' : '\(\\newif\)\@<!\\if\(field\|name\|numequal\)\@!'
\ }

then it does not work. Is that on purpose?

@mrajner
Copy link
Contributor Author

mrajner commented Mar 16, 2018

And about linewise. If you see some TeX mastery there could be many mixing conditionals statements in one line. And here vimtex failed (I just checked). But that should be no problem, as the package developer will do not want any indenting of this condensed statements.
The checking of undefined variables if often, but it works for example like

\ifdefined\myvar\else
  hello world!
\fi
So I will not bother nested if in one line.

@mrajner
Copy link
Contributor Author

mrajner commented Mar 16, 2018

and another exception (\ifthenelse)

'open' : '\(\\newif\)\@<!\\if\(field\|name\|numequal\|thenelse\)\@!'

lervag added a commit that referenced this issue Mar 19, 2018
@lervag
Copy link
Owner

lervag commented Mar 19, 2018

I've updated the default values per your suggestion, and I've also updated so you can set only a single key without affecting the other defaults.

Regarding linewise: I think it can be possible to implement support for more complex constructs. But I don't know how "necessary" it is. How often do people write such expressions without structuring it "logically"?

Please don't hesitate to open a new issue if you want me to look into supporting more complex constructs where the current implementation breaks.

@lervag lervag closed this as completed Mar 19, 2018
@mrajner
Copy link
Contributor Author

mrajner commented Mar 19, 2018

Yes, all works good. I do not really know why you prefer introducing another key 'disabled' instead of using empty dictionary to disable indenting of conditionals, but that is as I understand part of design (I think that this is not uniform within different settings in vimtex, thought).
I do not also think that more complex structures are really needed. Fortunately when \if\else are compound in one line, all works. Much more complicated nested, compacted conditionals are not likely in tex files (might be in classes and packages), and in my opinion are not worth of considering in advance.
Great solutions as for now.

@lervag
Copy link
Owner

lervag commented Mar 20, 2018

A moment of confusion from my part. I think checking for an empty dictionary is still better, so I'll revert that part. Thanks for raising the issue and for the useful comments!

@mrajner
Copy link
Contributor Author

mrajner commented Mar 20, 2018 via email

@lervag
Copy link
Owner

lervag commented Mar 20, 2018

I never mind direct suggestions, even though I sometimes wave my right to decide. In any case, the confusion was due to adding support for only overriding one of the keys, where I did not immediately notice that it still could and would work to allow disabling with an empty dict.

Again, thanks!

@mrajner
Copy link
Contributor Author

mrajner commented Mar 20, 2018 via email

@lervag
Copy link
Owner

lervag commented Mar 20, 2018

Good idea. But should this not also include =if?

@mrajner
Copy link
Contributor Author

mrajner commented Mar 20, 2018

if is working. Do not know why? Is is my hidden setting?

@lervag
Copy link
Owner

lervag commented Mar 20, 2018

Ah, yes, I think it is not necessary, because indentation occurs when typing <cr>, i.e. on the next line. No need to have the \if parts autoindent on the word. In any case, thanks, I'll update indentexpr.

@clason
Copy link
Contributor

clason commented Apr 1, 2018

Sorry to be that guy, but this broke indentation for me when using a macro \iff (for \Leftrightarrow). Is it possible to restrict the matches to non-math mode? Or can I disable this in my vimrc?)

@lervag
Copy link
Owner

lervag commented Apr 2, 2018

Yes, you can disable this. Add this to your vimrc file:

let g:vimtex_indent_conditionals = {
 \ 'open': '\v(\\newif)@<!\\if(f>|field|name|numequal|thenelse)@!',
\ }

The change is to add f>| to the default value, which should prevent \iff to start a conditional indent. You can also disable the entire feature with

let g:vimtex_indent_conditionals = {}

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

No branches or pull requests

3 participants