From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.ciao.gmane.io!not-for-mail From: =?utf-8?Q?K=C3=A9vin_Le_Gouguec?= Newsgroups: gmane.emacs.devel,gmane.emacs.orgmode Subject: [PATCH] Make RET and C-j obey `electric-indent-mode' in org-mode (was: Reconciling org-mode idiosyncrasies with Emacs core) Date: Wed, 06 May 2020 16:54:35 +0200 Message-ID: <877dxpazbo.fsf_-_@gmail.com> References: <20200426172206.GC18629@ACM> <87y2qhnc9a.fsf@gmail.com> <20200427102311.GA4976@ACM> <87mu6xtano.fsf@gmail.com> <87k120ohsq.fsf@mail.linkov.net> <87blnbir01.fsf@nicolasgoaziou.fr> <87o8rbmbfa.fsf@mail.linkov.net> <87k11yftqo.fsf@nicolasgoaziou.fr> <87pnbqo74t.fsf_-_@gmail.com> <87ees6fp8r.fsf@nicolasgoaziou.fr> <87y2q89dx7.fsf@gmail.com> <874ksv4uv1.fsf@nicolasgoaziou.fr> <87ftcfekxt.fsf@gmail.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="ciao.gmane.io:159.69.161.202"; logging-data="38891"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) To: Org Mode list , Emacs developers Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Wed May 06 16:55:17 2020 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jWLS8-000A1e-NF for ged-emacs-devel@m.gmane-mx.org; Wed, 06 May 2020 16:55:16 +0200 Original-Received: from localhost ([::1]:40470 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jWLS7-00035M-Oe for ged-emacs-devel@m.gmane-mx.org; Wed, 06 May 2020 10:55:15 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:35628) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jWLRZ-0002fd-Fa; Wed, 06 May 2020 10:54:41 -0400 Original-Received: from mail-wr1-x430.google.com ([2a00:1450:4864:20::430]:37026) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1jWLRY-0003U8-0n; Wed, 06 May 2020 10:54:41 -0400 Original-Received: by mail-wr1-x430.google.com with SMTP id k1so2573636wrx.4; Wed, 06 May 2020 07:54:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:references:date:in-reply-to:message-id:user-agent :mime-version; bh=9h12jFe/j7d1V0sT/8KxMHUNRbYkRynY/lsXNLa3hTU=; b=tB0ftOPTZAfLQn+TaTSJBH33OYbncGVP2gPRXi3nCwU+ZsUIZH/5lT4+/BmS2swQwA e1JHvnxejdbS/WyLf9jyMweRLyOsWJUNQfocUPScJa1wO5FJ1HQ8rMQ2ni02Amk6pKu9 bRB8zjfn0yLNWsaEW7BDYCYf0CRfFfYEo5Xi5dQNxhj2Z4WMPDvIZwFLXTCinPa2dYcX iH60qy2272Lz3L8qFWMCMWcQCllrmtRp8zgzZTktX/Mlh0PQ65Jz/+QJ+mtHxVtKgw3k Y4uWdMlNjkkwRW76EV6/f857r0/tCS81a4CdVESpyS+Ar0FrufEzWfIMOCsmvDrSOpgA hOig== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:references:date:in-reply-to :message-id:user-agent:mime-version; bh=9h12jFe/j7d1V0sT/8KxMHUNRbYkRynY/lsXNLa3hTU=; b=ry6FVrIXucp99OLnhdZW6gMclPlCy+8Z8vyrEtTtzz+efbFVJeIDlAxidTbFVXDQAW AfJN5X7MeXB7p7T7G+T0v6ebXza3Ntx3tog/AJjqqSn8rK3U+FxBgB9bgBwlUaoIsTMU 69PRnZnMccl6/yNZjXcPwhaMekjBkvNSLv4EvY4VgVaYtIp48CpTAPFfA5bM3OzJJRdt n1Adp26BkDmZhCNCDJR9bYpW/Qz2j3bxEzGDe2GRDcxBgIaORybZO2FJRZOaW+0kB5Dy T8ZxtNiI1x5vb975JfmC4IN9kdvtNgs9gcdDkYIZDvUJMhLGxZgVyPV2cH4L8iHJNiFj vvSw== X-Gm-Message-State: AGi0PubwH/ljplPpLE4gVDqERGqVBy5WdyAPjo/Thnel/V0aIbMgHDl6 fv+TlwfJC6XTOr4lfrm3whHwGjyNMJo= X-Google-Smtp-Source: APiQypIuPqnTAW6aCWCo9kPmV3ik7cZMoeLjeo8jkiIMlnE+eXESAloZK5PusQCOkKhO9o34mZEUyg== X-Received: by 2002:adf:f6cb:: with SMTP id y11mr9891848wrp.304.1588776877388; Wed, 06 May 2020 07:54:37 -0700 (PDT) Original-Received: from my-little-tumbleweed (200.143.13.109.rev.sfr.net. [109.13.143.200]) by smtp.gmail.com with ESMTPSA id h17sm3396878wmm.6.2020.05.06.07.54.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 06 May 2020 07:54:36 -0700 (PDT) In-Reply-To: <87ftcfekxt.fsf@gmail.com> (=?utf-8?Q?=22K=C3=A9vin?= Le Gouguec"'s message of "Mon, 04 May 2020 18:14:54 +0200") Received-SPF: pass client-ip=2a00:1450:4864:20::430; envelope-from=kevin.legouguec@gmail.com; helo=mail-wr1-x430.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_PASS=-0.001 autolearn=_AUTOLEARN X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:249092 gmane.emacs.orgmode:128894 Archived-At: --=-=-= Content-Type: text/plain Hello folks, Here's a complete patch to make RET and C-j honor electric-indent-mode in org-mode, targeting Org's master branch. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Make-RET-and-C-j-obey-electric-indent-mode.patch >From ec3b06f02aa875b3c78b076e846081ce4560ec18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Le=20Gouguec?= Date: Tue, 5 May 2020 19:01:07 +0200 Subject: [PATCH] Make RET and C-j obey `electric-indent-mode' * etc/ORG-NEWS: Announce the change. * lisp/org-compat.el (org-return-indent): Deprecate this command. * lisp/org-keys.el (org-mode-map): Rebind C-j to a command emulating `electric-newline-and-maybe-indent'. * lisp/org.el (org-cdlatex-environment-indent): Stop using the now obsolete function. (org--newline): New helper function. (org-return): Use it to transparently handle `electric-indent-mode'. (org-return-and-maybe-indent): New command to emulate `electric-newline-and-maybe-indent' while taking care of Org special cases (tables, links, timestamps). * testing/lisp/test-org.el (test-org/with-electric-indent, test-org/without-electric-indent): New tests. * testing/org-test.el (org-test-with-minor-mode): New helper to set a minor mode to a specific state, and reset it afterward. --- etc/ORG-NEWS | 33 +++++++++++++++++ lisp/org-compat.el | 9 +++++ lisp/org-keys.el | 2 +- lisp/org.el | 43 ++++++++++++++--------- testing/lisp/test-org.el | 76 ++++++++++++++++++++++++++++++++++++++++ testing/org-test.el | 9 +++++ 6 files changed, 155 insertions(+), 17 deletions(-) diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index c10e82f53..9c7e0d604 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -215,6 +215,32 @@ configured for ClojureScript will /not/ work. Babel Java blocks recognize header argument =:cmdargs= and pass its value in call to =java=. +*** =RET= and =C-j= now obey ~electric-indent-mode~ + +Since Emacs 24.4, ~electric-indent-mode~ is enabled by default. In +most major modes, this causes =RET= to reindent the current line and +indent the new line, and =C-j= to insert a newline without indenting. + +Org-mode now obeys this minor mode: when ~electric-indent-mode~ is +enabled, and point is neither in a table nor on a timestamp or a link: + +- =RET= (bound to ~org-return~) reindents the current line and indents + the new line; +- =C-j= (bound to the new command ~org-return-and-maybe-indent~) + merely inserts a newline. + +To get the previous behaviour back, disable ~electric-indent-mode~ +explicitly: + +#+begin_src emacs-lisp +(add-hook 'org-mode-hook (lambda () (electric-indent-mode -1))) +#+end_src + +*** New optional numeric argument for ~org-return~ + +In situations where ~org-return~ calls ~newline~, multiple newlines +can now be inserted with this prefix argument. + ** New commands *** ~org-table-header-line-mode~ @@ -303,6 +329,13 @@ Use ~org-hide-block-toggle~ instead. This function was not used in the code base, and has no clear use either. It has been marked for future removal. Please contact the mailing list if you use this function. + +*** Deprecated ~org-return-indent~ function + +In Elisp code, use ~(org-return t)~ instead. Interactively, =C-j= is +now bound to ~org-return-and-maybe-indent~, which indents the new line +when ~electric-indent-mode~ is disabled. + *** Removed ~org-maybe-keyword-time-regexp~ The variable was not used in the code base. diff --git a/lisp/org-compat.el b/lisp/org-compat.el index aae8efbd3..2b35535fa 100644 --- a/lisp/org-compat.el +++ b/lisp/org-compat.el @@ -678,6 +678,15 @@ an error. Return a non-nil value when toggling is successful." (goto-char (match-beginning 0)) (org-hide-block-toggle))))))) +(defun org-return-indent () + "Goto next table row or insert a newline and indent. +Calls `org-table-next-row' or `newline-and-indent', depending on +context. See the individual commands for more information." + (declare (obsolete "use `org-return' with INDENT set to t instead." + "Org 9.4")) + (interactive) + (org-return t)) + (defmacro org-with-silent-modifications (&rest body) (declare (obsolete "use `with-silent-modifications' instead." "Org 9.2") (debug (body))) diff --git a/lisp/org-keys.el b/lisp/org-keys.el index d358da763..7c0cc9216 100644 --- a/lisp/org-keys.el +++ b/lisp/org-keys.el @@ -618,7 +618,7 @@ COMMANDS is a list of alternating OLDDEF NEWDEF command names." (org-defkey org-mode-map (kbd "C-c C-k") #'org-kill-note-or-show-branches) (org-defkey org-mode-map (kbd "C-c #") #'org-update-statistics-cookies) (org-defkey org-mode-map (kbd "RET") #'org-return) -(org-defkey org-mode-map (kbd "C-j") #'org-return-indent) +(org-defkey org-mode-map (kbd "C-j") #'org-return-and-maybe-indent) (org-defkey org-mode-map (kbd "C-c ?") #'org-table-field-info) (org-defkey org-mode-map (kbd "C-c SPC") #'org-table-blank-field) (org-defkey org-mode-map (kbd "C-c +") #'org-table-sum) diff --git a/lisp/org.el b/lisp/org.el index 63de7306c..dbd072aff 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -15580,7 +15580,7 @@ environment remains unintended." ;; Get indentation of next line unless at column 0. (let ((ind (if (bolp) 0 (save-excursion - (org-return-indent) + (org-return t) (prog1 (current-indentation) (when (progn (skip-chars-forward " \t") (eolp)) (delete-region beg (point))))))) @@ -17647,20 +17647,31 @@ call `open-line' on the very first character." (org-table-insert-row) (open-line n))) -(defun org-return (&optional indent) +(defun org--newline (indent arg interactive) + "Call `newline-and-indent' or just `newline'. +If INDENT is non-nil, call `newline-and-indent' with ARG to +indent unconditionally; otherwise, call `newline' with ARG and +INTERACTIVE, which can trigger indentation if +`electric-indent-mode' is enabled." + (if indent + (newline-and-indent arg) + (newline arg interactive))) + +(defun org-return (&optional indent arg interactive) "Goto next table row or insert a newline. Calls `org-table-next-row' or `newline', depending on context. When optional INDENT argument is non-nil, call -`newline-and-indent' instead of `newline'. +`newline-and-indent' with ARG, otherwise call `newline' with ARG +and INTERACTIVE. When `org-return-follows-link' is non-nil and point is on a timestamp or a link, call `org-open-at-point'. However, it will not happen if point is in a table or on a \"dead\" object (e.g., within a comment). In these case, you need to use `org-open-at-point' directly." - (interactive) + (interactive "*i\nP\np") (let ((context (if org-return-follows-link (org-element-context) (org-element-at-point)))) (cond @@ -17711,30 +17722,30 @@ object (e.g., within a comment). In these case, you need to use (t (org--align-tags-here tags-column))) ;preserve tags column (end-of-line) (org-show-entry) - (if indent (newline-and-indent) (newline)) + (org--newline indent arg interactive) (when string (save-excursion (insert (org-trim string)))))) ;; In a list, make sure indenting keeps trailing text within. - ((and indent - (not (eolp)) + ((and (not (eolp)) (org-element-lineage context '(item))) (let ((trailing-data (delete-and-extract-region (point) (line-end-position)))) - (newline-and-indent) + (org--newline indent arg interactive) (save-excursion (insert trailing-data)))) (t ;; Do not auto-fill when point is in an Org property drawer. (let ((auto-fill-function (and (not (org-at-property-p)) auto-fill-function))) - (if indent - (newline-and-indent) - (newline))))))) + (org--newline indent arg interactive)))))) -(defun org-return-indent () - "Goto next table row or insert a newline and indent. -Calls `org-table-next-row' or `newline-and-indent', depending on -context. See the individual commands for more information." +(defun org-return-and-maybe-indent () + "Goto next table row, or insert a newline. +Call `org-table-next-row' or `org-return', depending on context. +See the individual commands for more information. + +When inserting a newline, indent the new line if +`electric-indent-mode' is disabled." (interactive) - (org-return t)) + (org-return (not electric-indent-mode))) (defun org-ctrl-c-tab (&optional arg) "Toggle columns width in a table, or show children. diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el index 2c78e1e23..d481d28e3 100644 --- a/testing/lisp/test-org.el +++ b/testing/lisp/test-org.el @@ -1310,6 +1310,82 @@ (org-return) (buffer-string))))) +(ert-deftest test-org/with-electric-indent () + "Test RET and C-j specifications with `electric-indent-mode' on." + ;; Call commands interactively, since this is how `newline' knows it + ;; must run `post-self-insert-hook'. + (org-test-with-minor-mode electric-indent-mode t + ;; RET, like `newline', should indent. + (should + (equal " Para\n graph" + (org-test-with-temp-text " Paragraph" + (call-interactively 'org-return) + (buffer-string)))) + (should + (equal "- item1\n item2" + (org-test-with-temp-text "- item1item2" + (call-interactively 'org-return) + (buffer-string)))) + (should + (equal "* heading\n body" + (org-test-with-temp-text "* headingbody" + (call-interactively 'org-return) + (buffer-string)))) + ;; C-j, like `electric-newline-and-maybe-indent', should not indent. + (should + (equal " Para\ngraph" + (org-test-with-temp-text " Paragraph" + (call-interactively 'org-return-and-maybe-indent) + (buffer-string)))) + (should + (equal "- item1\nitem2" + (org-test-with-temp-text "- item1item2" + (call-interactively 'org-return-and-maybe-indent) + (buffer-string)))) + (should + (equal "* heading\nbody" + (org-test-with-temp-text "* headingbody" + (call-interactively 'org-return-and-maybe-indent) + (buffer-string)))))) + +(ert-deftest test-org/without-electric-indent () + "Test RET and C-j specifications with `electric-indent-mode' off." + ;; Call commands interactively, since this is how `newline' knows it + ;; must run `post-self-insert-hook'. + (org-test-with-minor-mode electric-indent-mode nil + ;; RET, like `newline', should not indent. + (should + (equal " Para\ngraph" + (org-test-with-temp-text " Paragraph" + (call-interactively 'org-return) + (buffer-string)))) + (should + (equal "- item1\nitem2" + (org-test-with-temp-text "- item1item2" + (call-interactively 'org-return) + (buffer-string)))) + (should + (equal "* heading\nbody" + (org-test-with-temp-text "* headingbody" + (call-interactively 'org-return) + (buffer-string)))) + ;; C-j, like `electric-newline-and-maybe-indent', should indent. + (should + (equal " Para\n graph" + (org-test-with-temp-text " Paragraph" + (call-interactively 'org-return-and-maybe-indent) + (buffer-string)))) + (should + (equal "- item1\n item2" + (org-test-with-temp-text "- item1item2" + (call-interactively 'org-return-and-maybe-indent) + (buffer-string)))) + (should + (equal "* heading\n body" + (org-test-with-temp-text "* headingbody" + (call-interactively 'org-return-and-maybe-indent) + (buffer-string)))))) + (ert-deftest test-org/meta-return () "Test M-RET (`org-meta-return') specifications." ;; In a table field insert a row above. diff --git a/testing/org-test.el b/testing/org-test.el index 6904e16d1..69cdb905b 100644 --- a/testing/org-test.el +++ b/testing/org-test.el @@ -230,6 +230,15 @@ point at the beginning of the buffer." (delete-file file))))) (def-edebug-spec org-test-with-temp-text-in-file (form body)) +(defmacro org-test-with-minor-mode (mode state &rest body) + "Run BODY after setting MODE to STATE. +Restore MODE to its former state afterward." + (declare (debug (sexp sexp body)) (indent 2)) + `(let ((old-state ,mode)) + (,mode (if ,state 1 0)) + ,@body + (,mode (if old-state 1 0)))) + (defun org-test-table-target-expect (target &optional expect laps &rest tblfm) "For all TBLFM: Apply the formula to TARGET, compare EXPECT with result. -- 2.26.2 --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable To summarize (see also the patch's changelog message, and the ORG-NEWS entries which explain how to restore the current behaviour): - `org-return' (bound to RET) gains new arguments, and an interactive spec matching `newline'. - In situations where `org-return' must insert a newline, - if the INDENT argument is non-nil, `newline-and-indent' is called unconditionally, as before, - otherwise, `newline' is called with ARG and INTERACTIVE; if electric-indent-mode is on and INTERACTIVE is non-nil, this will trigger indentation. - `org-return-indent', the previous binding for C-j, is deprecated. - C-j is now bound to `org-return-and-maybe-indent', which calls (org-return t) when electric-indent-mode is disabled, and (org-return nil) otherwise. - In addition to the new unit tests, there is a new test helper to temporarily set or unset a minor mode. Let me know if I messed up something, or if there are things to tweak here and there. org-test-with-minor-mode might be overkill (and I am not used to writing macros, let alone edebug specs, so I might have goofed somewhere), but it does make the tests easier to read & write, so=E2=80=A6 =F0=9F=A4=B7 (I'm surprised such a macro does not already exist; did I miss it?) Thank you for your time. --=-=-=--