emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Syntax tables for multiple modes [was: bug#22983: syntax-ppss return


From: Vitalie Spinu
Subject: Re: Syntax tables for multiple modes [was: bug#22983: syntax-ppss returns wrong result.]
Date: Mon, 21 Mar 2016 17:45:38 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/25.0.91 (gnu/linux)

I have split the answer in two separate conceptually distinct parts. This one is
about indentation complexities of generic multi-modes.

>> On Mon, Mar 21 2016 10:43, Stefan Monnier wrote:

>> Current prog-indentation-context allows for possibility of a string to be
>> inserted before begging in of current chunk.  STRING-BEFORE is more more
>> general than that because of the arbitrary POS that it can be applied to.

> Good point.  I didn't think of that.  Do you make use of that
> possibility, and/or can you give an example where it's useful?

Please see example of erb mode below.

>> Here is a simple example when inner mode cannot decide by itself on
>> the indentation.  Assume for concreteness a noweb header with some code
>> immediately following the header:
>>
>>   <<foo, some_arg=4>>= some_call(blabla) 
>>       some_other_call(blabla) ## indented by offset 2 with respect to header 
>> or prev_chunk
>>
>> How do you indent the some_call(blabal) after the header? The most
>> meaningful way is to keep it untouched just as user defined it. If
>> inner mode would indent it by itself it would give offset of 4. This
>> is a simple example of header dependence.

> Maybe it's because I'm not familiar with noweb, but I didn't understand this
> example.  It looks like a very interesting example, so could you go over it
> again in much more detail?


Noweb is not essential here. The story will hold for pretty much all multi-modes
with non-full-line headers. In noweb `<<foo, some_arg=4>>=` is a header of a
chunk. Polymode places heads and tail in their own modes because they are not
conceptually part of nor host or sub-mode. You can specify arbitrary parameters
in the head which might even instruct how to indent the chunk. The first code
line `some_call(blabla)` is placed on the same line with the head. This is
uncommon but it's the simplest real case I can think of.

There are two issues here.

First one is how do you indent the head itself? Let's assume the point is after
`foo`. If you follow the naive prog-indentation-context the indentation should
be handled by the mode in the head chunk, right? Let's call it
noweb-head-mode. This mode is the same for many noweb host-mode/inner-mode
combinations and defaults to poly-head-tail-mode. Host mode is commonly LaTeX
but it can be anything. One reasonable way to indent it is to use the host mode
indentation engine. Note that this is in contrast of the
prog-indentation-context assumption for which PREVIOUS-CHUNK is assumed to be of
the same mode type as the current type.

The second issue is with respect to the first line immediately after the
header. If you naively call inner mode indentation engine on that line in a
narrowed buffer starting after >>= you will get it indented to FIRST-COLUMN,
which in the above case is the indentation of the head, plus noweb chunk offset
which is a polymode specific thing and it is customizable per inner mode. Do you
really want to insert that space after >>=? Probably not. So the code following
the header is special. That means that you will either have to take care of that
in multi-mode engine or extend prog-indentation-context.

Think of markdown simple code spans `this = is(a, codes, span)` which can occur
anywhere in the buffer. Indentation is not meaningful within the span at all,
the whole chunk should be indented by the outer mode just before the opening `.

Real trouble comes with continuation chunks. You might need to have a completely
reversed indentation logic - in outer/host spans MM engine needs to call inner
mode for indentation. Consider this example of erb mode taken from
https://github.com/fxbois/web-mode/blob/master/tests/demo.erb.

    <div id='header'>
      <% if signed_in? -%>
        <%= link_to t('.sign_out'), sign_out_path, :method => :delete %>
      <% else -%>
        <%= link_to t('.sign_in'), sign_in_path %>
      <% end -%>
    </div>

One meaningful approach here is to indent if-else-end block using inner mode
rules, right? This is what web-mode seems to be currently doing. Assume you are
just in front of `<%= link_to`. This is host hmtl mode. But you need to indent
according to inner mode construct. So what do you do? You go to the end of
previous code chunk and call prog-indentation-function of inner mode with
STRING-BEFORE = "\n" and STRING-AFTER="link_to t('.sign_out'), sign_out_path,
:method => :delete". Simple isn't it? That's precisely my proposal.

The message is that whatever you try you will not be able to completely leave
all the work to inner mode or capture it with naive constructs like
prog-indentation-context. Quite the opposite, new complexities are likely to
make multi-mode authors life harder.


  Vitalie




reply via email to

[Prev in Thread] Current Thread [Next in Thread]