From mboxrd@z Thu Jan 1 00:00:00 1970 From: Brent Goodrick Subject: Re: org-src--contents-for-write-back : preserve original major-mode, and avoid mixing tabs and spaces in org-mode buffers Date: Sat, 22 Apr 2017 20:21:07 -0700 Message-ID: References: <877f2cvnpe.fsf@nicolasgoaziou.fr> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Return-path: Received: from eggs.gnu.org ([2001:4830:134:3::10]:33429) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1d285H-00089U-1A for emacs-orgmode@gnu.org; Sat, 22 Apr 2017 23:21:12 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1d285F-0001uo-Hp for emacs-orgmode@gnu.org; Sat, 22 Apr 2017 23:21:11 -0400 Received: from mail-it0-x22f.google.com ([2607:f8b0:4001:c0b::22f]:35874) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1d285F-0001ug-BO for emacs-orgmode@gnu.org; Sat, 22 Apr 2017 23:21:09 -0400 Received: by mail-it0-x22f.google.com with SMTP id g66so24320153ite.1 for ; Sat, 22 Apr 2017 20:21:08 -0700 (PDT) In-Reply-To: <877f2cvnpe.fsf@nicolasgoaziou.fr> List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org Sender: "Emacs-orgmode" To: Nicolas Goaziou Cc: emacs-orgmode@gnu.org On Sat, Apr 22, 2017 at 1:41 AM, Nicolas Goaziou wrote: > > > The bug is in the `org-src--contents-for-write-back' function. It > > uses a temp buffer. The temp buffer's major-mode is left to be > > the default, which is fundamental-mode, which knows nothing about > > how to indent lisp code properly. > > And it doesn't need to. This function doesn't care about the code, but > indents it rigidly according to original source block. IOW, I don't > think changing the major mode is required. > > > So in the fix below, I run the major-mode function from the original > > buffer. But even with that fix, the indentation must also use spaces > > in order to avoid mixing tabs and spaces in the resulting Org buffer. > > Why do you think it is a good thing that tabs and spaces shouldn't be > mixed. For example, imagineh that the source code requires > `indent-tabs-mode' being non-nil, but Org source buffer indentation is > space only, i.e., with `indent-tabs-mode' being nil. Thanks for looking into this! In the current implementation of org-src--contents-for-write-back, the `with-temp-buffer` uses fundamental-mode. Later, while inside that temp buffer, spaces are inserted in to indent the entire source block over to where it needs to be (in my original post, notice that I have the source block within a list item so the source block needs to be aligned properly under that list item, no matter to what depth that list item is). It is in mode hook functions that certain changes to indentation can occur, so that is why I'm switching into that mode. But that is not enough: In order for the text to be aligned properly inside the org mode buffer after indentation, there cannot be a mix of tabs and spaces, as shown in my original post. IIRC, `indent-to' is called within the `write-back' function, and `indent-to' is affected by the `indent-tabs-mode' value, which by default in emacs lisp mode buffers, is t. You might try my implementation both without the change to `indent-tabs-mode' to see how improperly indented the resulting source block looks. > > Shouldn't the resulting block be indented with spaces from column 0 to > block boundaries' indentation, and then follow with space indentation? > Yes, if I understand what you are meaning. In fact, I think that is, in effect, what my replacement function is doing. Basically the bottom line is that you can't mix tabs and spaces in the final Org buffer and have it look correctly indented in that buffer, and the change to indent-tabs-mode to nil will be buffer local inside that with-temp-buffer so nothing is affected in any other buffer. For your reference, below is my replacement function that has elaborated comments that hopefully clarify things a bit more: (defun org-src--contents-for-write-back-fix-indentation () "Return buffer contents in a format appropriate for write back. Assume point is in the corresponding edit buffer." (let ((indentation (or org-src--block-indentation 0)) (preserve-indentation org-src--preserve-indentation) (contents (org-with-wide-buffer (buffer-string))) (write-back org-src--allow-write-back)) ;; --- BEGIN CHANGES FROM ORIGINAL DEFINITION --- ;; ;; Save off the original mode into orig-major-mode: ;; (let ((orig-major-mode major-mode)) (with-temp-buffer ;; ;; Insert the contents as was done before: ;; (insert (org-no-properties contents)) ;; ;; First change: Switch to the original mode for indentation by ;; switching its mode to be the original one. This is because that mode ;; handles mode-specific indentation behavior: ;; (funcall orig-major-mode) ;; ;; Second change: Do not use tabs here. If the mode being switched to ;; has indent-tabs-mode set to t, that is fine for separate buffers, but ;; for when org source blocks are shown in Org buffers, mixing tabs and ;; spaces will mess up the view (see this for emacs lisp code blocks ;; when indent-tabs-mode is set to t) when write-back calls `indent-to'. ;; ;; The alternative is to require everyone to set indent-tabs-mode to nil ;; in their mode hooks for all modes used in Org mode, but that seems ;; slightly heavy-handed. ;; (setq indent-tabs-mode nil) ;; --- END CHANGES FROM ORIGINAL DEFINITION --- (goto-char (point-min)) (when (functionp write-back) (funcall write-back)) (unless (or preserve-indentation (= indentation 0)) (let ((ind (make-string indentation ?\s))) (goto-char (point-min)) (while (not (eobp)) (when (looking-at-p "[ \t]*\\S-") (insert ind)) (forward-line)))) (buffer-string))))) I am curious to see if there is a better fix that what I've coded up above. Thanks again for your help, -Brent