0
votes

In my .emacs file I have the following function:

    ; Search for token forward and backward
    (defun search-token-forward()
      "Search forward for the ucode token at the point."
      (interactive) ; Makes the function available as a command
      (let (target-string)
        (setq target-string (buffer-substring 
                    (+ (re-search-backward "[^A-Za-z0-9/_.@#\$]") 1) 
                    (- (re-search-forward "[^A-Za-z0-9/_.@#\$]" nil t 2) 1)))
        ; post a message saying what we're looking for
        (message "Search for \`%s\`" target-string)
    ;    (setq case-fold-search nil)
        (search-forward target-string)))
    (global-set-key [f5]           'search-token-forward)

(defun search-token-backward()
  "Search backward for the ucode token at the point."
  (interactive)
  (point)
  (let (target-string)
    (setq target-string (buffer-substring 
                  (+ (re-search-backward "[^A-Za-z0-9/_.@#\$]") 1) 
                  (- (re-search-forward  "[^A-Za-z0-9/_.@#\$]" nil t 2) 1)))
    (message "backward search for \`%s\`" target-string)
;    (setq case-fold-search nil)
    ;
    ; here the search for the target string is done twice.  Once
    ; for the string that the cursor is on, and once more to go
    ; backwards for the next occurance.  
    ;
    (search-backward target-string nil nil 2)))
    (global-set-key [C-f5]           'search-token-backward)

After the first search the cursor moves till after the last character of the expression, which is fine since I can still do "search-token-backward" using another function that I have. Unfortunately, when searching after the last occurrence of the expression, the cursor moves to the end of line and so I can't smoothly try to search backwards since the cursor is not on the expression "position". What is causing this behavior and how is it possible to fix it?

Basically I would like the cursor to stay at the space after the last character of the expression even when there are no forward occurrences of it.

Here is an example: In the next code while the cursor is on the function foo_func I am clicking f5 which is tied to search-token-forward. The X marks where the cursor is after each click:

int foo_func(int w, int y);
       x cursor here to begin with.

some code...

foo_func(1, 2);
        x After first click
some code...   

foo_func(3,4);
        x after second click
some code...

return foo_func(5,6);
               x after third click

There are now no more occurences of foo_func in the file, so hitting f5 one more time moves the cursor one character to the right, like so:

return foo_func(5,6);
                x after forth click, this is the same line above.

So I can't simply hit ctrl-f5 to search backward for foo_func because the cursor is no more adjacent to the function.

2

2 Answers

1
votes

Record the last successful searched position found (see match-end). Pass t as the NOERROR arg, and if the return value is nil then you know that the string was not found, so you can return to the last successful position (actually, point should still be there).

Sorry, forget what I said there. I thought you were having a problem with search-forward. Your problem is no doubt coming up with the target string you are trying to search for. It's not clear what you really want to search for. As it is now, you are picking up the buffer text between these two places:

  • One char after the first char backward that is not any of these chars: A-Za-z0-9/_.@#\$.
  • One char before the second char forward that is not any of those same chars.

In case of failure, the second search there does not raise an error or advance the cursor from the start position.

I suspect that your current regexp for this is not what you want. Note, for instance, that it matches newline characters. Remember that inside [] (a character alternative), no characters are special, except ^ if it is first. See (elisp) Regexp Special.

Describe what text you are really trying to pick up from the buffer, to use as your search-forward search string (target-string). Specify it in English, and we will help you come up with how to pick it up from the buffer text. Maybe give an example of typical text that you have in the buffer, showing what part of it you want to pick up, to search for.

* UPDATE *

OK, either of these should do what you ask, I guess, but they are pretty ugly. (The second is a bit more robust.) You'd probably be better off starting from scratch...

 (defun search-token-forward()
   "..."
   (interactive)
   (let* ((opoint            (point))
          (case-fold-search  nil)
          (back              (re-search-backward "[^A-Za-z0-9/_.@#\$]"))
          (fwd               (re-search-forward "[^A-Za-z0-9/_.@#\$]" nil t 2))
          (target-string     (and back fwd (buffer-substring (+ back 1) (- fwd 1)))))
     (when target-string
       (message "Search for `%s'" target-string)
       (unless (search-forward target-string nil t)
         (goto-char opoint)
         (message "Search failed for `%s'" target-string)))))

 (defun search-token-forward()
   "..."
   (interactive)
   (let* ((opoint            (point))
          (case-fold-search  nil)
          (back              (re-search-backward "[^A-Za-z0-9/_.@#\$]"))
          (fwd               (re-search-forward "[^A-Za-z0-9/_.@#\$]" nil t 2))
          (target-string     (and back fwd (buffer-substring (+ back 1) (- fwd 1)))))
     (when target-string
       (message "Search for `%s'" target-string)
       (condition-case err
           (search-forward target-string)
         (search-failed (goto-char opoint) (error (error-message-string err)))))))

* UPDATE2 *

 (defun search-token-backward()
   "..."
   (interactive)
   (let ((opoint            (point))
         (case-fold-search  nil)
         back fwd target-string)
     (save-excursion
       (setq back  (re-search-backward "[^A-Za-z0-9/_.@#\$]")
             fwd   (re-search-forward "[^A-Za-z0-9/_.@#\$]" nil t 2)))
     (setq target-string  (and back  fwd
                               (buffer-substring (+ back 1) (- fwd 1))))
     (when target-string
       (message "Search for `%s'" target-string)
       (condition-case err
           (search-backward target-string)
         (search-failed (goto-char opoint) (error (error-message-string err)))))))
1
votes

I'm not debugging your elisp but giving other solutions on how to search a token forward.

1- Use evil's function

Evil-mode comes with that feature bound to *. It calls the function evil-search-symbol-forward (VS …-backward, bound to #).

You can call that function without using evil-mode if you don't want to. Install evil, require it in your ~/.emacs with (require 'evil), do NOT write (evil-mode 1) if you don't want to use the mode, then bound your keys to the given functions.

2- See post on Mastering Emacs

The author of that blog wrote an equivalent function: http://www.masteringemacs.org/articles/2013/10/31/smart-scan-jump-symbols-buffer/

Its advantage is that it has got two more features: to replace the symbol in the whole buffer or in the current defun.

ps: evil-goto-definition is quite handy too: Go to definition or first occurrence of symbol under point.