3

A formatted input file (*.alm) often contains a large section of columned data. To fold this and improve navigation, I've tried to implement a hs-special-mode-alist entry from hideshow.el.

(setq hs-special-modes-alist 
   '((alamo-mode "begin_data" "end_data" "#" alamo-forward-sexp nil)))

After executing the the bare bones mode in the footer and opening `test.alm',

# Name: test.alm
# Long comments
# Like this will fold

BEGIN_DATA # This will not fold 
1 2 3
1 2 3
1 2 3
END_DATA

running M-x hs-hide-all results in:

# Name: test.alm...

begin_data # This will not fold
1 2 3 
1 2 3
1 2 3
end_data

Despite my list declaration including a begin_data / end_data pairing, the block is ignored. I expected the buffer to look like:

# Name: test.alm...

begin_data ... end_data

Is there a reason why hideshow.el doesn't recognize and hide the begin_data / end_data block or am I missing something in my usage or declarations?

To fold test.alm load the following file:

;;; Demo code       
(defun alamo-forward-sexp (&optional arg)
  "Search forward to the next alamo option or begin/end of a data block.  
ARG defines the forward or backwards count for the search."
  (interactive "p")
  (or arg (setq arg 1))
  (re-search-forward "\\<\\(\\(begin\\|end\\)_data\\)\\>" nil nil arg))

(setq hs-special-modes-alist
      '((alamo-mode "begin_data" "end_data" "#" alamo-forward-sexp nil)))

;;;###autoload
(add-to-list 'auto-mode-alist '("\\.alm\\'" . alamo-mode))

;;;###autoload
(define-derived-mode alamo-mode prog-mode "ALAMO"
  "A major mode for editing ALAMO input files. (*.alm)"
(setq-local comment-start "#") ; required for hs-minor-mode
(hs-minor-mode 1))

(provide 'alamo-mode)
2

You did not implement alamo-forward-sexp correctly. If point is at begin_data almo-forward-sexp does not go to the block end, i.e., to the end of end_data but to the end of alamo-forward-sexp.

A fairly complete alamo-forward-sexp must treat nested sexps correctly. Something like that is most often done via a stack. Below I give a simple version of a stack based alamo-forward-sexp. Dislaimer: It does not treat comments.

(defun alamo-forward-one-sexp (&optional backward)
  "Search forward one alamo option or begin/end of a data block.
Search backward instead if BACKWARD is non-nil."
  (let (stack)
    (if backward
    (skip-chars-backward "[:space:]\n")
      (skip-chars-forward "[:space:]\n"))
    (if (if backward
        (and (looking-back "\\(^begin_data\\|\\s(\\)" nil)
         (goto-char (match-beginning 0)))
      (and (looking-at "\\(^begin_data\\|\\s(\\)")
           (goto-char (match-end 0))))
    (progn
      (push (list (match-string 0) (point)) stack)
      (while (and (> (length stack) 0)
              (if backward
              (re-search-backward "\\(^end_data\\|\\s)\\)\\|\\(^begin_data\\|\\s(\\)" nil t)
            (re-search-forward "\\(^begin_data\\|\\s(\\)\\|\\(^end_data\\|\\s)\\)" nil t))
              )
        (if (match-string 1) ;; opening a new sexp
        (push (list (match-string 0) (point)) stack)
          (pop stack) ;; TODO: error handling
          ))
      (when (> (length stack) 0)
        (signal 'scan-error (list "Unbalanced sexp boundaries." (cadar stack) (point)))))
      (if backward
      (skip-syntax-backward "w_")
    (skip-syntax-forward "w_")))))

(defun alamo-forward-sexp (&optional arg)
  "Search forward to the next alamo option or begin/end of a data block.
ARG defines the forward or backwards count for the search."
  (interactive "p")
  (if (> arg 0)
      (while (> arg 0)
    (alamo-forward-one-sexp)
    ;; (alamo--forward-sexp
    ;;  skip-chars-forward
    ;;  (looking-at "\\(^begin_data\\|\\s(\\)")
    ;;  (re-search-forward "\\(^begin_data\\|\\s(\\)\\|\\(^end_data\\|\\s)\\)" nil t)
    ;;  skip-syntax-forward)
    (decf arg))
    (while (> arg 0)
      (alamo-forward-one-sexp t)
      (decf arg))))

(setq hs-special-modes-alist
      '((alamo-mode "begin_data" "end_data" "#" alamo-forward-sexp nil)))

;;;###autoload
(add-to-list 'auto-mode-alist '("\\.alm\\'" . alamo-mode))

;;;###autoload
(define-derived-mode alamo-mode prog-mode "ALAMO"
  "A major mode for editing ALAMO input files. (*.alm)"
(setq-local comment-start "#") ; required for hs-minor-mode
(hs-minor-mode 1))

(provide 'alamo-mode)
  • Ah, I noticed that odd movement behavior but wasn't really sure if that was right or not. There are a lot of lot of good elisp things to dig into here. Thank you very much! – z-nut Jan 4 '18 at 20:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.