2017-12-16 16:37 GMT+03:00 Bram Moolenaar <[email protected]>:
>
> Nikolay Pavlov wrote:
>
>> 2017-12-15 22:09 GMT+03:00 Bram Moolenaar <[email protected]>:
>> >
>> > Many plugins set options to a different value.  To be able to restore
>> > the original value very often the old value needs to be saved.
>> >
>> > Not only is this a bit of a hassle, especially for local options, it is
>> > also incomplete, since the location where the option was originally set
>> > can't be restored.
>> >
>> > I have been thinking of adding two functions to make this work better:
>> >
>> > option_save({list})                                     *option_save()*
>> >                 Saves the options named in {list}.  The returned value can 
>> > be
>> >                 passed to option_restore().  Example: >
>> >                         let s:saved_options = option_save([
>> >                             \ 'ignorecase',
>> >                             \ 'iskeyword',
>> >                             \ ])
>> >                          au <buffer> BufLeave *
>> >                             \ call option_restore(s:saved_options)
>> > <               The advantage over using `:let` is that global and local
>> >                 values are handled and the script ID is restored, so that
>> >                 `:verbose set` will show where the option was originally 
>> > set,
>> >                 not where it was restored.
>> >
>> >
>> > option_restore({list})                                  *option_restore()*
>> >                 Restore options previously saved by option_save().
>> >                 When buffer-local options have been saved, this function 
>> > must
>> >                 be called when the same buffer is the current buffer.
>> >                 When window-local options have been saved, this function 
>> > must
>> >                 be called when the same window is the current window.
>> >                 When in the wrong buffer and/or window an error is given 
>> > and
>> >                 the local options won't be restored.
>> >
>> > Does that sound useful?
>>
>> AFAIK it was discussed before. Functions are too easy to forget to
>> call, especially given existence of excetpions and I don’t think that
>> “must be called when the same buffer … the same window …” is a good
>> idea either. Using context managers is a better option for the first
>> problem: you can forget ending `:with` block no more then you can
>> forget ending `:try`: i.e. forgetting will spawn an error at the point
>> where VimL does end the block even if `:endtry` was forgotten. Second
>> is nothing more then an annoing unnecessary nuisance, both buffers and
>> windows do have a unique identifiers and I do not see anything which
>> may prevent code from using them to find buffer/window to restore
>> option in, it is only needed to agree on behaviour in case that
>> buffer/window no longer exists.
>>
>> Context managers are also not limited to just options, they are
>> frequently used in Python for user code as well because this syntax is
>> in many cases more pleasant then `try … finally`.
>>
>> Also something like `:with setlocal iskeyword&vim|…|endwith` is much
>> nicer syntax then anything you can come up with based on VimL
>> expressions, with your proposal that would be
>>
>>     let saved_options = option_save(['iskeyword'])
>>     try
>>         setlocal iskeyword&vim
>>         …
>>     finally
>>         " Restore buffer/window here if needed.
>>         " Do not forget to check if it is.
>>         " Do not forget :try/finally if `…` is anything which may
>> throw an exception.
>>         " Do not forget :try/finally if `…` may throw an error as well
>> and user may have
>>         " a reason to call your function inside a `:try` block.
>> Basically do not forget it ever,
>>         " you may never know whether last statement is true.
>>         call option_restore(saved_options)
>>     endtry
>>
>> Putting my comments aside this is +2 lines for try/finally (endtry is
>> endwith, `let` line is `with` line), +1 line for `setlocal` (may be
>> good idea to devise different syntax, AFAIR I had something better
>> then `with setlocal iskeyword&vim`, i.e. more suitable for setting to
>> a value of an expression) and +1 line for `option_restore`, totalling
>> +4 lines.
>>
>> The only downside (from the user POV) I see is that you can’t split
>> calls up: i.e. have option_save() in one function and option_restore()
>> in another. From the developer POV I understand that context managers
>> are significantly harder to implement.
>
> You are talking about something else, a script that sets options, does
> its thing and then restores.  Without the user doing anything.
>
> What I was aiming at is a plugin, like netrw, which sets global options
> and restores them when switching to another window or when editing
> another buffer in the current window.  In the last case local options
> also need to be restored.

Temporary setting global option to be restored afterwards with
option_save()/option_restore() looks like a workaround for the case
“that option ought to be local, but it is not”. But it is a valid
concern, just I would suggest to solve it differently. Basically
Python’s :with context managers are syntax sugar for something like

    # original code: `with manager as w: …`
    v = manager.__enter__()
    try:
        …
    finally:
        manager.__exit__({exception data})

. If you won’t special-case saving/restoring options the syntax may look like

    with option_save('iskeyword', ['ignorecase', v:false], …)
        …
    endwith

which is

    let saved_options = option_save('iskeyword', ['ignorecase', v:false], …)
    try
        …
    finally
        call saved_options.exit()
    endtry

where option_save returns basically the same thing, but wrapped in a dictionary

    {
        'options': [
            {
                'name': 'iskeyword',
                'buffer': bufnr('%'),
                'value': '@,48-57,_,192-255',
                'snr': 1,
            },
            {
                'name': 'ignorecase',
                'value': v:true,
                " 'snr': omitted if setter not known
            },
        ],
        'exit': function('option_restore'),
    }

if some plugin actually needs to set the option temporary and reset
when gone to another buffer it will just desugarate :with and move
what it needed into another call. In my experience temporary setting
option for the duration of one function is far more common, though I
recognize the use-case.

>
> It should also work for an editing mode.  E.g., editing Vim script
> example in a help text file.  Then you would change 'shiftwidth' and
> some other settings, do some editing and restore when exiting the mode.
>
> We should probably also add a simple way to save and restore registers.
> getreg() and getregtype() almost do it, but you can't restore
> everything.

Restoring clipboard register is outright impossible as it is just a
pointer to another app and there are lots of ways to unintentionally
write to @". It is worth to have something like :keepregisters
(better, context manager with same meaning) which in addition to
saving and restoring internal registers will basically disable any
writes to system clipboard, regardless of what &clipboard setting is.
So one would be able to do `normal! gvy`, get @" register contents for
its purposes and still not make that spoil system clipboard.

>
> --
> hundred-and-one symptoms of being an internet addict:
> 103. When you find yourself in the "Computer" section of Barnes & Noble
>      enjoying yourself.
>
>  /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
> ///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
> \\\  an exciting new programming language -- http://www.Zimbu.org        ///
>  \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui