[Top][All Lists]

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

[Orgmode] PATCH: proposed improvements to org-src-mode

From: Dan Davison
Subject: [Orgmode] PATCH: proposed improvements to org-src-mode
Date: Tue, 11 Aug 2009 12:44:52 -0400
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/23.0.91 (gnu/linux)

I'm attaching a patch which attempts to make some improvements to
org-src-mode. A quick recap: currently, C-c ' on a source code block
displays the code in a language major mode buffer with minor mode
org-src-mode, which features the following two useful key-bindings:

| C-x s | org-edit-src-save | save the code in the source code block in the 
parent org file |
| C-c ' | org-edit-src-exit | return to the parent org file with new code       

Furthermore, while the edit buffer is alive, the originating code block
is subject to a special overlay which links to the edit buffer when you
click on it. This is all excellent, and I use it every day, but I think
there's still a couple of improvements that we should make.

Specifically, I'm proposing that the following are bugs:

* Proposed bug I
      C-x k kills the edit buffer without questions; the overlay
      remains, but now links to a deleted buffer.
* Proposed bug II
      C-x C-c kills a modified edit buffer silently, without offering to
      save your work. I have lost work like that a number of times
* Proposed bug III
      C-x s does not offer to save a modified edit buffer

The attached patch does the following.
- C-x s offers to save edit buffers
- C-x C-c offers to save edit buffers
- C-x k warns that you're killing an edit buffer
- If you do kill an edit buffer, the overlay in the parent buffer is removed
- Edit buffers are named *Org Src <orgbuf>[<lang>]*, where
  <orgbuf> is the name of the org-mode buffer containing this
  source code block, and lang is the language major mode.
- An internal detail is that org-edit-src-save is added to the
  write-contents-functions list, which means that it is no longer
  necessary to explicitly remap C-x C-s to org-edit-src-save

* Notes
  This patch gives the desired behaviour, at the cost of being forced to
  assign a buffer-file-name to the edit buffer. The consequence is that
  the edit buffer is considered to always be modified, since a file of
  that name is never actually written to (doesn't even exist). I didn't
  manage to come up with a way to trick emacs into holding the
  appropriate beliefs about whether the buffer had been modified. But in
  any case, I think there's an argument that these modifications
  warnings are a good thing, because one should not leave active edit
  buffers around: you should always have exited with C-c ' first.

Just in case it is helpful, I am including the notes I made in the
course of making these changes at the very bottom of the email.


p.s. In these two lines:
-  (unless (string-match "\\`*Org Edit " (buffer-name (current-buffer)))
-    (error "This is not an sub-editing buffer, something is wrong..."))
+  (unless org-edit-src-from-org-mode
+    (error "This is not a sub-editing buffer, something is wrong..."))

I assumed that org-edit-src-from-org-mode was an appropriate test. But
that may be incorrect as I am not certain what the intention was for
that variable.

--8<---------------cut here---------------start------------->8---
diff --git a/lisp/org-src.el b/lisp/org-src.el
index 2a6c087..a5816d2 100644
--- a/lisp/org-src.el
+++ b/lisp/org-src.el
@@ -113,7 +113,6 @@ but which mess up the display of a snippet in Org exported 
 (defvar org-src-mode-map (make-sparse-keymap))
 (define-key org-src-mode-map "\C-c'" 'org-edit-src-exit)
-(define-key org-src-mode-map "\C-x\C-s" 'org-edit-src-save)
 (defvar org-edit-src-force-single-line nil)
 (defvar org-edit-src-from-org-mode nil)
 (defvar org-edit-src-picture nil)
@@ -168,7 +167,8 @@ the edited version."
            (if (boundp 'org-edit-src-overlay)
                (org-delete-overlay org-edit-src-overlay)))
          (kill-buffer buffer))
-       (setq buffer (generate-new-buffer "*Org Edit Src Example*"))
+       (setq buffer (generate-new-buffer
+                     (concat "*Org Src " (file-name-nondirectory 
buffer-file-name) "[" lang "]*")))
        (setq ovl (org-make-overlay beg end))
        (org-overlay-put ovl 'face 'secondary-selection)
        (org-overlay-put ovl 'edit-buffer buffer)
@@ -186,8 +186,7 @@ the edited version."
                                '(display nil invisible nil intangible nil))
        (let ((org-inhibit-startup t))
-         (funcall lang-f)
-         (org-src-mode))
+         (funcall lang-f))
        (set (make-local-variable 'org-edit-src-force-single-line) single)
        (set (make-local-variable 'org-edit-src-from-org-mode) org-mode-p)
        (when lfmt
@@ -201,6 +200,7 @@ the edited version."
        (org-set-local 'org-edit-src-end-marker end)
        (org-set-local 'org-edit-src-overlay ovl)
        (org-set-local 'org-edit-src-nindent nindent)
+       (org-src-mode)
        (and org-edit-src-persistent-message
             (org-set-local 'header-line-format msg)))
       (message "%s" msg)
@@ -400,12 +400,13 @@ the language, a switch telling of the content should be 
in a single line."
 (defun org-edit-src-exit ()
   "Exit special edit and protect problematic lines."
-  (unless (string-match "\\`*Org Edit " (buffer-name (current-buffer)))
-    (error "This is not an sub-editing buffer, something is wrong..."))
+  (unless org-edit-src-from-org-mode
+    (error "This is not a sub-editing buffer, something is wrong..."))
   (let ((beg org-edit-src-beg-marker)
        (end org-edit-src-end-marker)
        (ovl org-edit-src-overlay)
        (buffer (current-buffer))
+       (buffer-file-name nil)
        (nindent org-edit-src-nindent)
        code line)
     (untabify (point-min) (point-max))
@@ -444,7 +445,6 @@ the language, a switch telling of the content should be in 
a single line."
     (switch-to-buffer (marker-buffer beg))
     (kill-buffer buffer)
     (goto-char beg)
-    (org-delete-overlay ovl)
     (delete-region beg end)
     (insert code)
     (goto-char beg)
@@ -464,6 +464,18 @@ the language, a switch telling of the content should be in 
a single line."
     (goto-char (min p (point-max)))
     (message (or msg ""))))
+(defun org-src-mode-configure-buffer ()
+  (setq buffer-offer-save t)
+  (setq buffer-file-name
+       (concat (buffer-file-name (marker-buffer org-edit-src-beg-marker))
+               "[" (buffer-name) "]"))
+  (set (if (featurep 'xemacs) 'write-contents-hooks 'write-contents-functions)
+       '(org-edit-src-save))
+  (org-add-hook 'kill-buffer-hook
+               '(lambda () (org-delete-overlay org-edit-src-overlay)) nil 
+(org-add-hook 'org-src-mode-hook 'org-src-mode-configure-buffer)
 (provide 'org-src)
 ;; arch-tag: 6a1fc84f-dec7-47be-a416-64be56bea5d8
--8<---------------cut here---------------end--------------->8---

* Notes on patch
*** write-contents-functions
    A good start seems to be to use org-src-mode-hook to add
    org-edit-src-save to the write-contents-functions list. This
    means that when it comes to saving, org-edit-src-save will be
    called and no subsequent attempt will be made to save the buffer
    in the normal way. (This should obviate the remapping of C-x C-s
    to org-edit-src-save in org-src.el)
*** buffer-offer-save
    We also want to set this to t.

*** Where does this get us?

    - C-x s still does *not* offer to save the edit buffer. That's
      because buffer-file-name is nil.
    - C-x C-c does ask us whether we want to save the
      edit buffer. However, since buffer-file-name is nil it asks us
      for a file name. The check in org-edit-src-exit throws an error
      unless the buffer is named '* Org Edit '...

    - C-x k kills the buffer silently, leaving a broken overlay
      link. If buffer-file-name were set, it would have warned that
      the buffer was modified.

*** buffer-file-name
    So, that all suggests that we need to set buffer-file-name, even
    though we don't really want to associate this buffer with a file
    in the normal way. As for the file name, my current suggestion
    is parent-org-filename[edit-buffer-name].
    [I had to move the (org-src-mode) call to the end of
    org-edit-src-code to make sure that the required variables were
    defined when the hook was called.]
*** And so where are we now?
    - C-x s *does* offer to save the edit buffer, but in saving
      produces a warning that the edit buffer is modified.
    - C-x k now gives a warning that the edit buffer is modified
      (even if it's not).
    - C-x C-c is working as desired, except that again we get
      warnings that the edit buffer is modified, once when we save,
      and again just before exiting emacs.
    - And C-c ' now issues a warning that the edit buffer is
      modified when we leave it, which we don't want.
*** So, we need to get rid of the buffer modification warnings.
    I've made buffer-file-name nil inside the let binding in
*** And?
    - C-x s behaves as desired, except that as was already the case,
      the edit buffer is always considered modified, and so repeated
      invocations keep saving it.
    - As was already the case, C-x k always gives a warning that the
      edit buffer has been modified.
    - C-x C-c is as desired (offers to save the edit buffer) except
      that it warns of the modified buffer just before exiting.
    - C-c ' is as it should be (silent)

Carsten Dominik <address@hidden> writes:

> Hi Dan,
> On Jun 2, 2009, at 5:02 PM, Dan Davison wrote:
>> Following on from the recent improvements to the *Org Edit Src
>> Example*
>> buffer, I have one more proposal: I have remapped C-x C-s so that it
>> saves the code in the org buffer, rather than offering to save the
>> Edit
>> buffer itself (as it used to be with the indirect edit buffer). I find
>> this essential, although I recognise that remapping C-x C-s is a
>> rather
>> radical thing to do to an emacs buffer.
> But allowed:  From the Emacs lisp docs, under Major Mode Conventions:
>      It is legitimate for a major mode to rebind a standard key
>      sequence if it provides a command that does "the same job" in a
>      way better suited to the text this mode is used for.
> I'd say, your's is a perfect example for this rule.
>> I am using the simple-minded approach below; it seems to work fine (I
>> don't even notice a flicker -- should I be surprised at that?), but if
>> someone can suggest an improved implementation I'd be happy to learn
>> how
>> it should be done (perhaps there are buffer variables other than point
>> and mark that I should restore? Is there a general mechanism I should
>> use for this?).
>> Dan
>> (defun org-edit-src-save ()
>>  "Update the parent org buffer with the edited source code, save
>> the parent org-buffer, and return to the source code edit
>> buffer."
>>  (interactive)
>>  (let ((p (point))
>>      (m (mark)))
>>    (org-edit-src-exit)
>>    (save-buffer)
>>    (org-edit-src-code)
>>    (set-mark m)
>>    (goto-char p)))
> This is already excellent.  I have changed it only slightly,
> in order to get a better message when this command finishes, and
> because `push-mark' should be used here instead of `set-mark'.
> (defun org-edit-src-save ()
>   "Save parent buffer with current state source-code buffer."
>   (interactive)
>   (let ((p (point)) (m (mark)) msg)
>     (org-edit-src-exit)
>     (save-buffer)
>     (setq msg (current-message))
>     (org-edit-src-code)
>     (push-mark m 'nomessage)
>     (goto-char p)
>     (message (or msg ""))))
> I have added your code, thanks.
> - Carsten

reply via email to

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