1

I currently use emacs for UVM testbench environment development. I use verilog-mode with solarized theme. I like my current setup, however I would like to improve the functionality of emacs.

I would like to add fold-unfold functionality for block of code / comment.

for e.g. I've a class as follows

class myClass ;
   function myFunction
     // variable define
     // more variable define

     begin
    //line 1
    //line 2
    //line 3
     end

      begin
     //line1
     //line2
     //line3
      end

   endfunction //
endclass // myClass

If I'm working with 2nd (bottom) begin-end block, I would like to fold 1st one (top) Anything followed by // is a comment and can be replaced with actual code. Can I achieve this with emacs?

wisemonkey
  • 571
  • 3
  • 15
  • 29
  • You're asking too many questions at once. Try to break it down and approach each one separately. I'll get you started: For general-purpose version control, the built-in `VC` mode is excellent. It's a unified interface to a number of version control systems. There are other options for specific systems as well; for instance, I use Magit for Git. – ChrisGPT was on strike Mar 31 '14 at 00:15
  • I'm afraid this sort of thing is explicity called out as being a type of question to avoid in [what not to ask](http://stackoverflow.com/help/dont-ask) "If your motivation for asking the question is “I would like to participate in a discussion about ______”, then you should not be asking here." – Richard Tingle Mar 31 '14 at 00:16
  • Is what you're looking for a software recommendation, or are you gathering ideas for a feature request to emacs? – Richard Tingle Mar 31 '14 at 00:18
  • Thanks for responses, I didn't want to break it in multiple questions because I wanted all information in one place to refer to. I completely understand Stackoverflow is not a place for this type of question, however I couldn't think of any other place. I thought stackoverflow would get most exposure and if not answers I may at least get a starter as to where to look / ask for these features. @RichardTingle I want to use emacs as an IDE for UVM development so I'm looking for all available options. – wisemonkey Mar 31 '14 at 04:46
  • I'm going to break the question in 5 different question one per feature in original question, I'll edit the same question to start with. – wisemonkey Mar 31 '14 at 16:21
  • Code folding requires a specific beginning and a specific ending -- a regexp is used to locate the beginning / ending points. Here is a link to my `toggle-block` function for LaTeX where the beginning regexp is `\begin{anything}` and the ending regexp is `\end{anything}`. http://tex.stackexchange.com/a/161196/26911 – lawlist Mar 31 '14 at 16:37
  • Thanks @lawlist I'll try to understand that and see what I can do. Systemverilog has multiple begin and end for block for e.g. begin-end, function-endfunction, task-endtask, class-endclass, module-endmodule and so on, I'll try your method and update keywords properly. I'll let you know how that works. – wisemonkey Mar 31 '14 at 17:17
  • I read through your answer it seems I'll need outline mode and some knowledge of emacs lisp to implement something similar, is that correct? Can I look at your function implementation somewhere? Screenshots would be enough – wisemonkey Mar 31 '14 at 21:03

2 Answers2

1

Here is an example that uses \begin{anything} and \end{anything} for the beginning and ending regexp that is used by the function toggle-block to determine what two points to use to fold everything between those two points. The original poster could modify beg-flag-regexp to be something like function1\\|function2\\|function3\\|function4 and the ending regexp would be something like endfunction. The beginning point should probably be just after function1 so that function1 remains visible when the code block is folded. Additional tweaking / modification to this function would be needed to suit the precise needs of the original poster, but this example should help demonstrate the general concept behind using outline-flag-region from the outline library.

(defvar beg-flag-regexp (concat
  "\\(\\\\begin\{\\)\\("
  "[^}]*"
  "\\)\\(\}\\)" )
"Regexp matching the beginning of the folded region.")

(defun toggle-block ()
"When FLAG is non-nil, hide the region.  Otherwise make it visible.  For this
function to work, the cursor must be on the same line as the beginning regexp."
(interactive)
  (require 'outline)
  (cond
    ((or
        ;; sweet-spot
        (looking-at beg-flag-regexp)
        ;; point could be between backslash and before the letter n
        (let ((line-begin (save-excursion (beginning-of-line 1) (point))))
          (save-excursion
            (re-search-backward "\\\\" line-begin t)
            (looking-at beg-flag-regexp)))
        ;; point could be to the right of \begin
        (let ((line-begin (save-excursion (beginning-of-line 1) (point))))
          (save-excursion
            (re-search-backward "\\\\begin" line-begin t)
            (looking-at beg-flag-regexp)))
        ;; point could be to the left of \begin
        (let ((line-end (save-excursion (end-of-line 1) (point))))
          (save-excursion
            (re-search-forward "\\\\begin" line-end t)
            (backward-char 6)
            (looking-at beg-flag-regexp))))
      (let* (
          (flag (not (get-char-property (match-end 0) 'invisible)))
          (beg (match-end 0))
          end
          (base-flag-match (regexp-quote
            (buffer-substring-no-properties (match-beginning 2) (match-end 2))))
          (end-flag-match (concat "\\\\end\{" base-flag-match "\}"))
          (go-fish (concat "\\begin\{" base-flag-match "\}"))  )
        (save-excursion
          (if (re-search-forward end-flag-match nil t)
            (progn
              (setq end (point))
              (outline-flag-region beg end flag)
              (cond
                (flag
                  (overlay-put (make-overlay beg end) 'display "\u25be"))
                (t
                  (mapc 'delete-overlay (overlays-in beg end)))))
            (user-error "Error locating an ending match for:  %s." go-fish)))
        (if (> (point) beg)
          (goto-char beg)) ))
    (t
      (message "Sorry, you are not on a line containing the beginning regexp."))))

Step One:  Paste the entire code for the variable beg-flag-regexp and the function toggle-block into the .emacs file, and restart Emacs.

Step Two:  Open up an empty buffer, and type M-x text-mode RET

Step Three:  Copy and paste the following examples into the buffer you just created:

\begin{wisemonkey}Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus convallis sodales sapien, ut vulputate tellus mollis vel. Aenean accumsan leo est, nec euismod sem imperdiet blandit. In sed consequat mi, in convallis arcu. Vestibulum ultrices lectus nec nisi malesuada hendrerit. Proin molestie placerat rutrum. Donec gravida, ligula sit amet luctus interdum, nisl quam tempus sem, eget varius lacus orci ac sapien. Nulla in metus non neque condimentum blandit. Phasellus sed est a tellus fermentum viverra vulputate non dui. Integer vel tempor nisi. Phasellus turpis lectus, gravida sit amet ornare faucibus, sollicitudin quis metus.

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed hendrerit commodo consectetur. Mauris sollicitudin ut sapien a interdum. Maecenas ac nibh sodales, adipiscing leo a, dictum turpis. Sed vestibulum odio id pulvinar rhoncus. Ut fringilla lacus at egestas semper. Nulla aliquet eleifend quam, nec varius tortor tincidunt at. Donec non vehicula tortor, eu congue augue. Nulla a nisi hendrerit, tincidunt sapien eget, accumsan mauris. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.\end{wisemonkey}

\begin{lawlist} Nunc sapien elit, gravida in felis non, volutpat lacinia quam. Nulla ut sagittis turpis. Curabitur faucibus ullamcorper felis, eget hendrerit dolor. Donec volutpat, nisi at condimentum posuere, nulla justo blandit tortor, a rhoncus odio augue id dolor. Praesent sit amet aliquam risus. Praesent odio velit, dignissim eget tincidunt nec, ultricies ut est. Morbi sit amet pellentesque ipsum. Ut vitae laoreet mauris. Donec lobortis auctor tortor, id faucibus urna luctus quis. Praesent vel sollicitudin mi. Sed neque mi, ultrices nec erat ut, congue convallis ante. Sed eu ipsum blandit, porttitor libero ac, volutpat est.

Phasellus gravida urna at ante pretium, sed interdum sem elementum. Maecenas congue purus nec aliquam lobortis. Praesent lacinia ac libero at eleifend. Mauris nec blandit ante. Integer accumsan et elit vitae scelerisque. Maecenas hendrerit, elit quis facilisis rhoncus, mi justo adipiscing erat, vitae pellentesque dui purus eu magna. Vestibulum tincidunt, lacus vitae molestie hendrerit, quam justo feugiat odio, eu ullamcorper risus sem vitae lacus. Vestibulum sit amet nunc in dolor placerat congue hendrerit vel augue. Vivamus ac odio ut purus malesuada gravida eget a dolor. Nullam sit amet nisi congue, lobortis lacus eu, varius ante. Donec vehicula lacinia elit ac condimentum. Aliquam egestas adipiscing orci in pharetra. Curabitur pulvinar tincidunt neque, non tempus nisi volutpat eget. Nulla tincidunt egestas libero, a pharetra orci ullamcorper fermentum. Nulla nec nunc nec urna semper tristique. Proin est dolor, sodales ut pretium eu, luctus a magna. \end{lawlist}

Step Four:  To fold the text, place the cursor anywhere on the line of code containing \begin{wisemonkey} or \begin{lawlist} and type M-x toggle-block

Step Five:  To unfold the text, simply repeat Step Four.


Example
(source: lawlist.com)

Example
(source: lawlist.com)

Example
(source: lawlist.com)


EXAMPLE # 2

(defun wisemonkey ()
"When FLAG is non-nil, hide the region.  Otherwise make it visible.  For this
function to work, the cursor must be on the same line as the beginning regexp."
(interactive)
  (require 'outline)
  (cond
    ((let ((line-end (save-excursion (end-of-line 1) (point))))
      (save-excursion
        (beginning-of-line 1)
        (re-search-forward "function" line-end t)))
      (let* (
          (beg (save-excursion (end-of-line 1) (point)))
          (flag (not (get-char-property beg 'invisible)))
          end
          (end-flag-match "endfunction"))
        (save-excursion
          (if (re-search-forward end-flag-match nil t)
            (progn
              (setq end (point))
              (outline-flag-region beg end flag)
              (cond
                (flag
                  (overlay-put (make-overlay beg end) 'display "\u25be"))
                (t
                  (mapc 'delete-overlay (overlays-in beg end)))))
            (user-error "Error locating an ending match for:  `function`.")))
        (if (> (point) beg)
          (goto-char beg)) ))
    (t
      (message "Sorry, you are not on a line containing the beginning regexp."))))
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
lawlist
  • 13,099
  • 3
  • 49
  • 158
  • Thanks this worked, I'll try few other combinations over the week and report back / ask for feedback around weekend :) – wisemonkey Apr 01 '14 at 16:05
  • I'm trying to understand your code, I read very little about emacs lisp over last few days. And it seems in your code (\begin{)(.*}) are 2 groups and both must match to indicate start of block however if I simply want to fold everything between begin and end (there is no \ in front or {text} after). I thought I don't need concat function so (defvar beg-flag-regexp "\\\(begin\\\)") Is that correct? If yes how would line with go-fish function change? – wisemonkey Apr 05 '14 at 22:56
  • If you update your question with a specific beginning regexp and a specific ending regexp, it would be much easier for me to assist you -- use a real life example of something you want to accomplish. To experiment with `(outline-flag-region beg end flag)`, the `beg` is just a point like `154` and `end` is another point like `256` and `flag` is either `t` or `nil`. Example -- **HIDE**: `(outline-flag-region 154 256 t)`. Example -- **SHOW**: `(outline-flag-region 154 256 nil)`. The let-bound variable `go-fish` is just for purposes of generating an error message if applicable. – lawlist Apr 05 '14 at 23:17
  • The variable `beg-flag-regexp` does not need to be concatenated. – lawlist Apr 05 '14 at 23:21
  • Thanks, I've updated the question, basically in systemverilog we have multiple start of block (begin, function, task, class, module, covergroup, fork etc.) and each have their own stop (end, endfunction, endtask, endclass, endmodule, endgroup, join etc.) If you can show me one fold-unfold example. I'll just create multiple functions for each pair – wisemonkey Apr 05 '14 at 23:53
  • I've modified the answer with second example, which uses the beginning regexp of `function` and the ending regexp of `endfunction`. – lawlist Apr 06 '14 at 00:47
  • Is there a way to make complete line visible? for e.g. `function myFunction` (everything until new line) stays visible when folded. I appreciate all your help – wisemonkey Apr 06 '14 at 01:26
  • 1
    Sure -- the beginning point just needs to be to the right of `myFunction`. But how do we *always* know the name of `myFunction` to search for it with `re-search-forward`? If we do not know the name of `myFunction`, perhaps `beg` could *always* be at the end of the line containing the word `function`? But if there are comments after `myFunction`, then it is *not* technicaly the end of the line -- so perhaps go to the end of the line and search backward for the comments and set the point at the beginning of the comment (but after `myFunction`) . . . – lawlist Apr 06 '14 at 01:31
  • function name doesn't always need to be `myFunction`. `function blah blah blah [newline]` should stay visible when folded so `function .*\n` (its a made up regex -- means function followed by anything until newline) is the start ? – wisemonkey Apr 06 '14 at 01:41
  • 1
    I've posted a revised second example that uses the end of the first line (of the beginning regexp) for the beginning point of the fold. – lawlist Apr 06 '14 at 02:20
  • I've created all functions in one file, can you please upload the file at github or some place so anybody can use it? – wisemonkey Apr 07 '14 at 19:20
  • 1
    Anyone is certainly free to use and/or modify any code that I post to Stackoverflow / Superuser / Stackexchange / Github. I normally spend more time debugging and perfecting code before I post it to Github. In the context of this particular example function, I would probably want to create one function that can handle all situations -- rather than multiple functions. I would want the function to examine the beginning regexp to know what ending regexp to look for. In short, it's not ready for prime-time -- :) -- it was just a working example to be further perfected by you or anyone else ... – lawlist Apr 07 '14 at 19:47
  • Anyone can create a free Github account -- it only takes a few minutes to setup :) You can use an internet web browser to copy / paste / edit. As to the fold/hide function, a useful feature might be for the folding to occur so long as the cursor (aka point) is anywhere between the beginning and ending regexp. – lawlist Apr 07 '14 at 19:48
  • yes creating single function would be the best solution, I'll think about how to do it but my elisp knowledge is very limited. I'll keep you updated if I manage to change anything. – wisemonkey Apr 07 '14 at 20:31
0

I got this in my config file, you can have a try:

(setq hs-special-modes-alist
      (cons '(verilog-mode "\\<begin\\>\\|\\<task\\>\\|\\<function\\>\\|\\<class\\>\\|\\<module\\>\\|\\<package\\>"
                           "\\<end\\>\\|\\<endtask\\>\\|\\<endfunction\\>\\|\\<endclass\\>\\|\\<endmodule\\>\\|\\<endpackage\\>"
                           nil
                           verilog-forward-sexp-function)
            hs-special-modes-alist))
Enze Chi
  • 1,733
  • 17
  • 28