unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* paren-close-dwim: elisp function of a newbie; feedback welcome
@ 2013-09-25 11:46 Florian
  2013-09-25 12:18 ` Andreas Röhler
  2013-09-25 17:32 ` Davis Herring
  0 siblings, 2 replies; 11+ messages in thread
From: Florian @ 2013-09-25 11:46 UTC (permalink / raw)
  To: emacs-devel

Hi,

here is my first elisp function 'paren-close-dwim' and I would be glad
to get some feedback on it (whether its done to complicated, in an
unusual way, or whether this functionality is already available in
some emacs extension which I have not found).

The function allows to close braces/brackets/paranthesis without the
user to care which kind of brace actually has to be closed next. For
me this is much handier than using paren-mode or auto-pair etc,
especially when modifying existing code. Automatic paren modes came in
the way and did the wrong thing from time to time for me and I had to
delete automatically inserted closing paranthesis which was hindering
my workflow. So, to be honest, I were not able to master them
appropriately enough with my muscle memory.

I work with a German keyboard layout where braces are not that easily
reachable as on the Englisch layout, but I want to stick with this and
just want to avoid some uncomfortable key-strokes for closing braces.

So, here is my function paren-close-dwim, which you can freely pick
and use for your own configuration.  Maybe it is a bit
'over-commented', which only represents my still lacking elisp
fluency.

(defun paren-close-dwim ()
  "Insert the next missing closing paranthesis based on the syntax table.
   Otherwise insert a normal closing ?\)"
  (interactive)
  (save-excursion
    (setq fallback-char ?\))
    ;; go backward up a level in the parenthesis hierarchy (which
    ;; jumps to the next not yet closed (seen from point) open
    ;; parenthesis). Catch unbalanced paranthesis error etc.
    (setq closing-paren
          (condition-case nil
              (progn (backward-up-list)
                     ;; get character at point
                     (setq open-paren (point))
                     ;; get corresponding closing character from the
                     ;; syntax table. (syntax-after open-paren)
                     ;; delivers a cons cell with (OPEN . CLOSE), so
                     ;; we need the cdr to match open-paren.
                     (setq syntax-cons (syntax-after open-paren))
                     (if (cdr syntax-cons)
                         (cdr syntax-cons)
                       ;; if cdr is nil use the fallback-char
                       fallback-char))
            (error fallback-char))))
    ;; insert dwim parenthesis
    (insert closing-paren))

;; I bind this to the normal closing paranthesis key and am quite happy
;; with its behaviour in several different modes since a few weeks now.
(global-set-key (kbd ")") 'paren-close-dwim)

Thanks for your feedback,
Florian



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: paren-close-dwim: elisp function of a newbie; feedback welcome
  2013-09-25 11:46 paren-close-dwim: elisp function of a newbie; feedback welcome Florian
@ 2013-09-25 12:18 ` Andreas Röhler
  2013-09-25 17:32 ` Davis Herring
  1 sibling, 0 replies; 11+ messages in thread
From: Andreas Röhler @ 2013-09-25 12:18 UTC (permalink / raw)
  To: emacs-devel

Am 25.09.2013 13:46, schrieb Florian:
> Hi,
>
> here is my first elisp function 'paren-close-dwim' and I would be glad
> to get some feedback on it (whether its done to complicated, in an
> unusual way, or whether this functionality is already available in
> some emacs extension which I have not found).
>
> The function allows to close braces/brackets/paranthesis without the
> user to care which kind of brace actually has to be closed next. For
> me this is much handier than using paren-mode or auto-pair etc,
> especially when modifying existing code. Automatic paren modes came in
> the way and did the wrong thing from time to time for me and I had to
> delete automatically inserted closing paranthesis which was hindering
> my workflow. So, to be honest, I were not able to master them
> appropriately enough with my muscle memory.
>
> I work with a German keyboard layout where braces are not that easily
> reachable as on the Englisch layout, but I want to stick with this and
> just want to avoid some uncomfortable key-strokes for closing braces.
>
> So, here is my function paren-close-dwim, which you can freely pick
> and use for your own configuration.  Maybe it is a bit
> 'over-commented', which only represents my still lacking elisp
> fluency.
>
> (defun paren-close-dwim ()
>    "Insert the next missing closing paranthesis based on the syntax table.
>     Otherwise insert a normal closing ?\)"
>    (interactive)
>    (save-excursion
>      (setq fallback-char ?\))
>      ;; go backward up a level in the parenthesis hierarchy (which
>      ;; jumps to the next not yet closed (seen from point) open
>      ;; parenthesis). Catch unbalanced paranthesis error etc.
>      (setq closing-paren
>            (condition-case nil
>                (progn (backward-up-list)
>                       ;; get character at point
>                       (setq open-paren (point))
>                       ;; get corresponding closing character from the
>                       ;; syntax table. (syntax-after open-paren)
>                       ;; delivers a cons cell with (OPEN . CLOSE), so
>                       ;; we need the cdr to match open-paren.
>                       (setq syntax-cons (syntax-after open-paren))
>                       (if (cdr syntax-cons)
>                           (cdr syntax-cons)
>                         ;; if cdr is nil use the fallback-char
>                         fallback-char))
>              (error fallback-char))))
>      ;; insert dwim parenthesis
>      (insert closing-paren))
>
> ;; I bind this to the normal closing paranthesis key and am quite happy
> ;; with its behaviour in several different modes since a few weeks now.
> (global-set-key (kbd ")") 'paren-close-dwim)
>
> Thanks for your feedback,
> Florian
>
>

Hi Florian,

IMO that's quite interesting, thanks.

In detail some design suggestions:

- use let-bound variables instead of setq closing-paren
- don't rely on syntax-table (xclusively), rather make it an universal command, relying on chars
   that would permit also to close "}" for example, being usable in text-modes.
   skip-chars-backward MY-DELIMITER_CHARS seems an option.

Andreas






^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: paren-close-dwim: elisp function of a newbie; feedback welcome
  2013-09-25 11:46 paren-close-dwim: elisp function of a newbie; feedback welcome Florian
  2013-09-25 12:18 ` Andreas Röhler
@ 2013-09-25 17:32 ` Davis Herring
  2013-09-26 19:54   ` Harry Putnam
  1 sibling, 1 reply; 11+ messages in thread
From: Davis Herring @ 2013-09-25 17:32 UTC (permalink / raw)
  To: Florian; +Cc: emacs-devel

> (defun paren-close-dwim ()
>   "Insert the next missing closing paranthesis based on the syntax table.

Typo: "parenthesis".

>    Otherwise insert a normal closing ?\)"

Don't indent docstring lines.

>   (interactive)

Use "*" to get an immediate error if read-only.  You might also consider
allowing a prefix count like `self-insert-command'.

>   (save-excursion
>     (setq fallback-char ?\))

Use `let' to introduce local variables.  However, here you'll be able to
do without any...

>     ;; go backward up a level in the parenthesis hierarchy (which
>     ;; jumps to the next not yet closed (seen from point) open
>     ;; parenthesis). Catch unbalanced paranthesis error etc.
>     (setq closing-paren
>           (condition-case nil
>               (progn (backward-up-list)
>                      ;; get character at point
>                      (setq open-paren (point))
>                      ;; get corresponding closing character from the
>                      ;; syntax table. (syntax-after open-paren)
>                      ;; delivers a cons cell with (OPEN . CLOSE), so
>                      ;; we need the cdr to match open-paren.
>                      (setq syntax-cons (syntax-after open-paren))

Since you only assign and use `open-paren' once, just insert the
expression for it in place of the variable.

>                      (if (cdr syntax-cons)
>                          (cdr syntax-cons)
>                        ;; if cdr is nil use the fallback-char
>                        fallback-char))

(or (cdr syntax-cons) fallback-char)

This then allows you to drop the `syntax-cons' variable.

>             (error fallback-char))))

Use `ignore-errors' and promote the `or`:

(or (ignore-errors (backward-up-list) (cdr (syntax-after (point))))
    fallback-char)

Then you can get rid of `fallback-char' too.

>     ;; insert dwim parenthesis
>     (insert closing-paren))


Similarly, you can do without the `closing-paren' variable.

Indentation error: the `insert' is not inside the `save-excursion'.

The final version I get (narrowly wrapped for email):

(defun paren-close-dwim ()
  "Insert closing parenthesis from syntax table.
Use a normal parenthesis if not inside any."
  (interactive "*")
  (insert (or (ignore-errors
                (save-excursion (backward-up-list)
                                (cdr (syntax-after (point)))))
              ?\))))

Davis

-- 
This product is sold by volume, not by mass.  If it appears too dense or
too sparse, it is because mass-energy conversion has occurred during
shipping.



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: paren-close-dwim: elisp function of a newbie; feedback welcome
  2013-09-25 17:32 ` Davis Herring
@ 2013-09-26 19:54   ` Harry Putnam
  2013-09-26 20:38     ` Davis Herring
  0 siblings, 1 reply; 11+ messages in thread
From: Harry Putnam @ 2013-09-26 19:54 UTC (permalink / raw)
  To: emacs-devel

Davis Herring <herring@lanl.gov> writes:

> (defun paren-close-dwim ()
>   "Insert closing parenthesis from syntax table.
> Use a normal parenthesis if not inside any."
>   (interactive "*")
>   (insert (or (ignore-errors
>                 (save-excursion (backward-up-list)
>                                 (cdr (syntax-after (point)))))
>               ?\))))

I'm a total illiterate in elisp but the narrative so far sounds like a
this code might do something really useful.

Can someone describe briefly how this would work, maybe with a small
example, when repairing my own perl code?




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: paren-close-dwim: elisp function of a newbie; feedback welcome
  2013-09-26 19:54   ` Harry Putnam
@ 2013-09-26 20:38     ` Davis Herring
  2013-09-26 20:44       ` Florian
  2013-09-27 21:30       ` Harry Putnam
  0 siblings, 2 replies; 11+ messages in thread
From: Davis Herring @ 2013-09-26 20:38 UTC (permalink / raw)
  To: Harry Putnam; +Cc: emacs-devel

>> (defun paren-close-dwim ()
>>   "Insert closing parenthesis from syntax table.
>> Use a normal parenthesis if not inside any."
>>   (interactive "*")
>>   (insert (or (ignore-errors
>>                 (save-excursion (backward-up-list)
>>                                 (cdr (syntax-after (point)))))
>>               ?\))))
> 
> I'm a total illiterate in elisp but the narrative so far sounds like a
> this code might do something really useful.
> 
> Can someone describe briefly how this would work, maybe with a small
> example, when repairing my own perl code?

I'm not sure what you mean about "repairing ... code".  This command
simply inserts ')', ']', or '}' (and perhaps '>' or so) to match the
most recent unclosed ([{<.

(If it is "really useful", know that it's not my idea; you just quoted
my reimplementation of Florian's code.)

Davis

-- 
This product is sold by volume, not by mass.  If it appears too dense or
too sparse, it is because mass-energy conversion has occurred during
shipping.



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: paren-close-dwim: elisp function of a newbie; feedback welcome
  2013-09-26 20:38     ` Davis Herring
@ 2013-09-26 20:44       ` Florian
  2013-09-27  5:51         ` Andreas Röhler
                           ` (2 more replies)
  2013-09-27 21:30       ` Harry Putnam
  1 sibling, 3 replies; 11+ messages in thread
From: Florian @ 2013-09-26 20:44 UTC (permalink / raw)
  To: emacs-devel


> I'm not sure what you mean about "repairing ... code".  This command
> simply inserts ')', ']', or '}' (and perhaps '>' or so) to match the
> most recent unclosed ([{<.
> 
> (If it is "really useful", know that it's not my idea; you just quoted
> my reimplementation of Florian's code.)

But yours is much cleaner, I like it. Thanks for that.

Here is a small example to illustrate what it does:

If you are writing a nested expression, like the following, and '_' is
your cursor,

{ (a * [(b) - (c) _

and you have bound ')' to paren-close-dwim (dwim = do what I mean),
three succeeding presses of ')' will produce the sequence: ])}. Or in
other words: ')' will produce the correct next matching closing
bracket regarding the position of your cursor.

Florian




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: paren-close-dwim: elisp function of a newbie; feedback welcome
  2013-09-26 20:44       ` Florian
@ 2013-09-27  5:51         ` Andreas Röhler
  2013-09-29  9:36           ` Ted Zlatanov
  2013-09-27 21:33         ` Harry Putnam
  2013-09-29 10:11         ` Óscar Fuentes
  2 siblings, 1 reply; 11+ messages in thread
From: Andreas Röhler @ 2013-09-27  5:51 UTC (permalink / raw)
  To: emacs-devel

Am 26.09.2013 22:44, schrieb Florian:
>
>> I'm not sure what you mean about "repairing ... code".  This command
>> simply inserts ')', ']', or '}' (and perhaps '>' or so) to match the
>> most recent unclosed ([{<.
>>
>> (If it is "really useful", know that it's not my idea; you just quoted
>> my reimplementation of Florian's code.)
>
> But yours is much cleaner, I like it. Thanks for that.
>
> Here is a small example to illustrate what it does:
>
> If you are writing a nested expression, like the following, and '_' is
> your cursor,
>
> { (a * [(b) - (c) _
>
> and you have bound ')' to paren-close-dwim (dwim = do what I mean),
> three succeeding presses of ')' will produce the sequence: ])}. Or in
> other words: ')' will produce the correct next matching closing
> bracket regarding the position of your cursor.
>
> Florian
>
>
>

Really great. So we may have an electric-close, where C-j does all remaining before reaching the next line.





^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: paren-close-dwim: elisp function of a newbie; feedback welcome
  2013-09-26 20:38     ` Davis Herring
  2013-09-26 20:44       ` Florian
@ 2013-09-27 21:30       ` Harry Putnam
  1 sibling, 0 replies; 11+ messages in thread
From: Harry Putnam @ 2013-09-27 21:30 UTC (permalink / raw)
  To: emacs-devel

Davis Herring <herring@lanl.gov> writes:

>>> (defun paren-close-dwim ()
>>>   "Insert closing parenthesis from syntax table.
>>> Use a normal parenthesis if not inside any."
>>>   (interactive "*")
>>>   (insert (or (ignore-errors
>>>                 (save-excursion (backward-up-list)
>>>                                 (cdr (syntax-after (point)))))
>>>               ?\))))
>> 
>> I'm a total illiterate in elisp but the narrative so far sounds like a
>> this code might do something really useful.
>> 
>> Can someone describe briefly how this would work, maybe with a small
>> example, when repairing my own perl code?
>
> I'm not sure what you mean about "repairing ... code".  This command
> simply inserts ')', ']', or '}' (and perhaps '>' or so) to match the
> most recent unclosed ([{<.

It was actually a reference to something Florian said in OP:

Florian wrote:
>> .  .  .  .  .  .  .  .  .  .  .  .  For me this is much handier
>> than using paren-mode or auto-pair etc, especially when modifying
>> existing code."

In my mind that registered as `repairing code'.

> (If it is "really useful", know that it's not my idea; you just quoted
> my reimplementation of Florian's code.)

Thanks, yes, sorry... I actually meant to be replying to Florian's OP.




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: paren-close-dwim: elisp function of a newbie; feedback welcome
  2013-09-26 20:44       ` Florian
  2013-09-27  5:51         ` Andreas Röhler
@ 2013-09-27 21:33         ` Harry Putnam
  2013-09-29 10:11         ` Óscar Fuentes
  2 siblings, 0 replies; 11+ messages in thread
From: Harry Putnam @ 2013-09-27 21:33 UTC (permalink / raw)
  To: emacs-devel

Florian <floriansbriefe@gmail.com> writes:

> Here is a small example to illustrate what it does:

[...] snipped example.

Thank you, that was exactly what I needed to understand its working.




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: paren-close-dwim: elisp function of a newbie; feedback welcome
  2013-09-27  5:51         ` Andreas Röhler
@ 2013-09-29  9:36           ` Ted Zlatanov
  0 siblings, 0 replies; 11+ messages in thread
From: Ted Zlatanov @ 2013-09-29  9:36 UTC (permalink / raw)
  To: emacs-devel

On Fri, 27 Sep 2013 07:51:11 +0200 Andreas Röhler <andreas.roehler@online.de> wrote: 

AR> Am 26.09.2013 22:44, schrieb Florian:
>> 
>> If you are writing a nested expression, like the following, and '_' is
>> your cursor,
>> 
>> { (a * [(b) - (c) _
>> 
>> and you have bound ')' to paren-close-dwim (dwim = do what I mean),
>> three succeeding presses of ')' will produce the sequence: ])}. Or in
>> other words: ')' will produce the correct next matching closing
>> bracket regarding the position of your cursor.

AR> Really great. So we may have an electric-close, where C-j does all remaining before reaching the next line.

This is a great idea (both `paren-close-dwim' and the electric version
of it).  IMHO `paren-close-dwim' should go into Emacs, not an external
package, and have first-class key bindings.  It's really helpful.

Ted




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: paren-close-dwim: elisp function of a newbie; feedback welcome
  2013-09-26 20:44       ` Florian
  2013-09-27  5:51         ` Andreas Röhler
  2013-09-27 21:33         ` Harry Putnam
@ 2013-09-29 10:11         ` Óscar Fuentes
  2 siblings, 0 replies; 11+ messages in thread
From: Óscar Fuentes @ 2013-09-29 10:11 UTC (permalink / raw)
  To: emacs-devel

Florian <floriansbriefe@gmail.com> writes:

[snip]

> If you are writing a nested expression, like the following, and '_' is
> your cursor,
>
> { (a * [(b) - (c) _
>
> and you have bound ')' to paren-close-dwim (dwim = do what I mean),
> three succeeding presses of ')' will produce the sequence: ])}. Or in
> other words: ')' will produce the correct next matching closing
> bracket regarding the position of your cursor.

I'll like to match the space separators too. With your example, pressing
`)' thrice would result in:

{ (a * [(b) - (c)]) }_

Note how the space between `(c) _' disappeared and how an space was
inserted before `}'.

Without this sub-feature, the user would be forced to edit after
pressing `)'.




^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2013-09-29 10:11 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-09-25 11:46 paren-close-dwim: elisp function of a newbie; feedback welcome Florian
2013-09-25 12:18 ` Andreas Röhler
2013-09-25 17:32 ` Davis Herring
2013-09-26 19:54   ` Harry Putnam
2013-09-26 20:38     ` Davis Herring
2013-09-26 20:44       ` Florian
2013-09-27  5:51         ` Andreas Röhler
2013-09-29  9:36           ` Ted Zlatanov
2013-09-27 21:33         ` Harry Putnam
2013-09-29 10:11         ` Óscar Fuentes
2013-09-27 21:30       ` Harry Putnam

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).