Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

preserve indent-tabs-mode in markdown-edit-code-block #816

Open
froh opened this issue Nov 21, 2023 · 5 comments
Open

preserve indent-tabs-mode in markdown-edit-code-block #816

froh opened this issue Nov 21, 2023 · 5 comments

Comments

@froh
Copy link

froh commented Nov 21, 2023

Expected Behavior

When I edit a nested code block using markdown-edit-code-block and I reindent it in the edit-indirect buffer, it's indentation should be preserved when I commit the edit back to the markdown document.

Actual Behavior

The indent-rigidly in markdown--edit-indirect-after-commit-function gets a region indented according to the default settings of indent-tabs-mode and tab-width, which may easily mismatch the markdown document's settings (in my case: markdown set to indent with spaces, default however is tabs). poor indent-rigidly can't but mess up at this time.

Steps to Reproduce

  1. create markdown document with a nested code block, nested deep enough
  2. edit it (C-c ')
  3. indent it (C-M-q)
  4. commit back (C-c C-c)

see the broken indentation. I have a simple solution proposal, so no cut&paste example.

Backtrace

Software Versions

  • markdown-mode-version: "2.7-alpha" from melpa
  • Emacs: GNU Emacs 27.1 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.33, cairo version 1.16.0)
    of 2023-08-16, modified by Debian
  • OS: ubuntu 22.04 LTS on wsl
@froh
Copy link
Author

froh commented Nov 21, 2023

proposed fix: preserve the relevant buffer-local settings, see ===>> and <<===

(defun markdown-edit-code-block ()
  "Edit Markdown code block in an indirect buffer."
  (interactive)
  (save-excursion
    (if (fboundp 'edit-indirect-region)
        (let* ((bounds (markdown-get-enclosing-fenced-block-construct))
               (begin (and bounds (not (null (nth 0 bounds))) (goto-char (nth 0 bounds)) (line-beginning-position 2)))
               (end (and bounds(not (null (nth 1 bounds)))  (goto-char (nth 1 bounds)) (line-beginning-position 1))))
          (if (and begin end)
              (let* ((indentation (and (goto-char (nth 0 bounds)) (current-indentation)))
                     (original-indent-tabs-mode indent-tabs-mode) ;;; ====>>
                     (original-tab-width tab-width)  ;;; =====>>
                     (lang (markdown-code-block-lang))
                     (mode (or (and lang (markdown-get-lang-mode lang))
                               markdown-edit-code-block-default-mode))
                     (edit-indirect-guess-mode-function
                      (lambda (_parent-buffer _beg _end)
                        (funcall mode)))
                     (indirect-buf (edit-indirect-region begin end 'display-buffer)))
                ;; reset `sh-shell' when indirect buffer
                (when (and (not (member system-type '(ms-dos windows-nt)))
                           (member mode '(shell-script-mode sh-mode))
                           (member lang (append
                                         (mapcar (lambda (e) (symbol-name (car e)))
                                                 sh-ancestor-alist)
                                         '("csh" "rc" "sh"))))
                  (with-current-buffer indirect-buf
                    (sh-set-shell lang)))
                (when (> indentation 0) ;; un-indent in edit-indirect buffer
                  (with-current-buffer indirect-buf
                    (setq indent-tabs-mode original-indent-tabs-mode) ;;; <<====
                    (setq tab-width original-tab-width)  ;;; <<====
                    (indent-rigidly (point-min) (point-max) (- indentation)))))
            (user-error "Not inside a GFM or tilde fenced code block")))
      (when (y-or-n-p "Package edit-indirect needed to edit code blocks. Install it now? ")
        (progn (package-refresh-contents)
               (package-install 'edit-indirect)
               (markdown-edit-code-block))))))

alternative:

create some markdown--edit-indirect-after-create-function which copies select local variables.
the hook then needs to access the edit-indirect internal edit-indirect--overlay

@syohex
Copy link
Collaborator

syohex commented Nov 22, 2023

Could you show us how to reproduce in detail ? How are indentations broken ? Original code, broken indentation code etc.

@froh
Copy link
Author

froh commented Nov 22, 2023

here is some badly indented markdown

# abcdefg
 * How does it work?
    * Design rationales

       * ...

    * Architecture patterns

       * monolith, embedding python, C++, Java in single image

    * Diagrams

       * plain JNA, cython, operation dispatch in C++/cython like data store

         ``` plantuml
         @startuml
         !theme cb_seq_Greens_9 from https://raw.githubusercontent.com/mweagle/C4-PlantUML-Themes/main/palettes
         !include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Component.puml
         !include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

         LAYOUT_AS_SKETCH()

         System_Boundary(sb, "fastest possible:\nflow coordination in C++,\nFFI plain JNA, cython") {

            Container_Boundary(cpp, "C++ world", "C++", "operations in C++:\nhigh performance") {
               Component(A.cpp, "A.cc", "C++", "some operation A")
              Container_Boundary(flow, "flow coordination") {
             Component(cpp_flow, "flow", "C++", "flow core library")
               }
               Container_Boundary(store, "fast object store", "C++ library\npy, JVM bindings", "shared blackboard:\ninsanely fast data exchange") {
                  Component(cpp_store, "object store core library", "C++ .so")
                  ComponentDb(store_memory, "object store shared memory", "shared memory")
                  Rel_D(cpp_store, store_memory, "control and own")
               }
            }

            Container_Boundary(py, "Python world", "Python", "operations in Python:\nrapid development") {
            Component(B.py, "B.py", "Python", "some operation B")
              Component(python_store, "store API\nPython wrapper", "cython")
             Component(python_flow, "flow API\nPython wrapper", "cython")
            }

            Container_Boundary(java, "Java world", "Java", "operations in Java:\nmassive existing infrastructure") {
          Component(C.java, "C.java", "Java", "some operation C")
          Component(java_store, "store API\nJava wrapper", "JNA")
               Component(java_flow, "flow API\nJava wrapper", "JNA")
            }

            BiRel_U(A.cpp, cpp_flow, "invoke", "native, .so")

            BiRel_U(B.py, python_flow, "invoke", "python")
            BiRel_U(python_flow, cpp_flow, "invoke", "cython")

            BiRel_U(C.java, java_flow, "invoke", "Java")
            BiRel_U(java_flow, cpp_flow, "invoke", "JNA")

            BiRel_D(A.cpp, cpp_store, "invoke", "native .so")
            Rel_D(A.cpp, store_memory, "R/W", "native .so")

            Rel_D(B.py, python_store, "interact", "python")
            BiRel_D(python_store, cpp_store, "invoke", "cython")
            Rel_D(python_store, store_memory, "R/W", "cython")

            Rel_D(C.java, java_store, "interact", "Java")
            BiRel_D(java_store, cpp_store, "invoke", "JNA")
            Rel_D(java_store, store_memory, "R/W", "JNA")

         }

         SHOW_FLOATING_LEGEND()
         Lay_Distance(A.cpp, LEGEND(), 1)
         @enduml

         ```
    * some more
    
 * and on it goes

<!--  LocalWords:  diff
  Local Variables:
  markdown-asymmetric-header: t
  indent-tabs-mode: nil
  mode: gfm
  End:
 -->

  1. prepare test

    • system default ìndent-tabs-modeshall be the installation default,t`
    • package-install plantuml-mode, edit-indirec from melpa (for puml indent, edit indirect)
  2. double check indent-tabs-mode (shall be nil)

  3. edit code block C-c '

  4. in the edit-indirect buffer

    • check indent-tabs-mode (should be t, the system default)
    • the mode should be plantuml-mode .
    • go to opening curly brace, reindent C-M-q
  5. search for tabs C-s C-q i

  6. save or commit (C-x C-s / C-c C-c)

==> broken indent

@syohex
Copy link
Collaborator

syohex commented Nov 30, 2023

How about using edit-indirect-after-creation-hook and write your own customizations ? I think it is impossible to support all modes to preserve such variables because some modes use their own offset level and tab variables instead of indent-tabs-mode, tab-width. And I'm not sure everyone expects the behavior you suggest.

@froh
Copy link
Author

froh commented Nov 30, 2023

I see the point of "which variables to move over"?. And I can use the hook, of course.

for the time being would you advise to use this stanza to capture the values from the original buffer?

(with-current-buffer (overlay-buffer edit-indirect--overlay) ;;; this feels like hijacking an internal variable
      (save-excursion
         ...))

In the description of the hooks it was unspecific which buffer you're in when each hook is invoked and how to access the "other" buffer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants