emacs-devel
[Top][All Lists]
Advanced

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

Re: A vision for multiple major modes: some design notes


From: Phillip Lord
Subject: Re: A vision for multiple major modes: some design notes
Date: Fri, 22 Apr 2016 13:45:48 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/25.0.92 (gnu/linux)

Alan Mackenzie <address@hidden> writes:
>> When you say "complementary" do you mean alternative or simultaneous?
>> I.e. will an island always be enclosed by syntax markers and always have
>> a text property. Or can it have either?
>
> Sorry, that wasn't very clear.  It would always have both.  The text
> property would enable the code for chain local variables quickly to
> determine the current chain.  The syntactic markers would enable
> efficient scanning by parse-partial-sexp, etc.
>
>> I'm still not understanding how the chain of islands is set up. Is this
>> entirely the super modes responsibility?
>
> Yes, it would be entirely for the super mode to do.  There would be a
> set of functions to do this, for example:
>
>     (defun create-island-chain (beg end major-mode ...) ...)  (where BEG
>     and END would be the bounds of the first island in the chain).
>
>     (defun add-island-to-chain (chain beg end ...) ...)  (which would
>     delimit (BEG END) as an island, and link it into CHAIN)
>
> There would also be functions for removing islands from a chain, etc.  I
> should really have put this into the notes.  Thanks!


I think that you would need some good utility functions, and call backs
to support this though. Say, I have a mode with some syntactic markers
identifing islands. Who has the job of checking that the islands are
still the same?

I had this problem with "lentic" -- and it's hard work. You need to hook
into the various change functions, and sometimes rescan the entire
buffer. Using the change functions is a PITA anyway, and easy to get
wrong. And, avoiding scanning the whole buffer after every change is
good to avoid.

Font-lock avoids this, for instance, by getting core Emacs to tell each
mode when to re-fontifify different regions. I think you would need
something similar.




>> Also, how will the regexp engine work when it spans an island? I ask
>> because, if we use the regexp engine to match delimiters, the which
>> syntax do we use, if there are multiple modes in the buffer.
>
> I imagine that the island-start/end syntactic markers would normally be
> set by the super mode as syntax-table text properties.  These always
> take priority over whatever the current syntax table would say.  These
> markers would be considered to be in the enclosing scope, not part of
> the island they define.
>
> The current syntax table would always be that of the island the current
> position was in.  I suppose there is potential for an island to be
> recognised as such in the "enclosing scope", but not in the island
> itself.  This could be mitigated against by warning super mode
> programmers to use island-start/end syntaxes ONLY in syntax-table text
> properties.
>
> The actual matching of an island to "\\s-" would be delegated to the
> syntax code (as is currently done for "\\s?" expressions).

I am worried about syntax codes in general. Say, we have a syntax like

#+begin_src lisp

#+end_src


Whether "_" is a symbol constituent or not is mode specific. Say, we
have a buffer with mixed org-mode and lisp. The regexp we need to
identify #+end_src will depend on the mode of the buffer that #+end_src
is in. That is the point of course.

But, if you are using #+end_src to delineate islands in the first place,
then what mode the text is in rather indeterminate -- you cannot
guarantee that the islands are in the correct place yet, because this is
why you are looking for #+end_src markers. So, you have to build a
regexp which does not use char classes which differ between modes.

For this to work, I think, you need to be able to say to regexp
functions "ignore islands". Binding "in-islands" to nil might work I
guess.




>
>> >   o - An island might be represented by a C or Lisp structure, it might not
>> >     (not yet decided).  This structure would hold the containing chain,
>> >     markers pointing to the start and end of the chain, and the previous 
>> > and
>> >     next islands in the chain.
>> >
>> > (v) Syntax, etc.
>> >   o - Two new syntax classes, "open island" and "close island" will be
>> >     introduced.  These will be designated by the characters "{" and "}".  
>> > Their
>> >     "matching character" slots will contain the island's chain.  There 
>> > will be
>> >     an extra flag "chain" (denoted by "i") indicating whether there is a
>> >     previous/next island in the chain.
>> >   o - `scan-lists', `scan-sexps', etc. will treat a "foreign" island as
>> >     whitespace, much as they do comments.  They will also treat as 
>> > whitespace
>> >     the gap between two islands in a chain.
>
>> Difficult to say, but this might produce some counter intuitive
>> behaviour. So, for example, consider some text like so:
>
>> === Example
>
>> (here is some lisp)
>
>
>> ;; This is a long and tedious piece of documentation in my lisp program.
>> (here is some more lisp)
>
>
>> === End Example
>
>> Now moving backward a paragraph will have a significant difference in
>> behaviour -- on the "(" of "here is some more lisp", we move to "(here
>> is some lisp), while on the char before, we move the "This is a long".
>> Good, bad, expected? Don't know.
>
> Assuming that the comment is set up as an island inside the lisp code
> (which might not be the Right Thing to do) ....
>
> As a user action, moving back that paragraph would move from "(here is
> some more lisp)" to ";; This is a long ....", since `in-islands' would
> be nil during command processing.
>
> As part of a program's parsing, `in-islands' would be bound to non-nil,
> and backward-paragraph would move from "(here is some more lisp)" to
> "(here is some lisp)".
>
> This is the intended processing.
>
> [ .... ]
>
>> > (vii) Variables.
>> >   o - Island chain local variable bindings will come into existence.  These
>> >     bindings depend on the island point is in.  There will be lower level
>> >     routines that will have "position" parameters as an alternative to 
>> > using
>> >     point.
>> >   o - All variables which are currently buffer local will become chain 
>> > local
>> >     except for those whose symbols are given a non-nil `entire-buffer'
>> >     property.  There will be no new functions like
>> >     `make-chain-local-variable'.
>
>> What is the default-value of a chain local variable, if the variable is
>> also buffer-local?
>
> This would be the (global) default value of the variable.  It would not
> be the buffer-local value.  The intention is that the buffer-local value
> is the value for the portions of the buffer which are not in any
> islands.
>
>> Will we need functions for setting all chains in a certain mode in a
>> single buffer?
>
> I'm not sure what you mean, here.  Does "in a certain mode" mean "INTO a
> certain mode"?


Oh. Say I have a buffer, half in clojure mode, half in markdown mode. I
start cider which connects to a REPL. Currently, cider sets a
buffer-local variable called something like "cider-connected-to-repl-p"
to "t" to indicate the connection.

But, now, we have an island local variable instead. But, surely, if one
island is connected to a repl, then all the others should be as well.




> If so, setting a major or minor mode in a chain will be
> able to be done by putting point inside a pertinent island and calling
> the mode function.  Maybe a new function `mapchains' could be useful.


Yep, that sort of idea.

Phil



reply via email to

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