Commits

Frank Fischer committed ff05a8f

add jumps

  • Participants
  • Parent commits 1250012

Comments (0)

Files changed (4)

File vim-commands.el

   "Sets the mark `mark-char' at point."
   (vim:set-mark mark-char))
 
+(defun vim:print-mark-list (marks)
+  "Prints information about the alist marks."
+  (mapconcat
+   #'(lambda (mark)
+       (let ((show-buffer-name
+	      (not (eq (current-buffer) (marker-buffer (cdr mark))))))
+	 (with-current-buffer (marker-buffer (cdr mark))
+	   (save-excursion
+	     (goto-char (cdr mark))
+	     (let ((file-or-text
+		    (if show-buffer-name (buffer-name)
+		      (let* ((beg (save-excursion
+				    (vim:motion-first-non-blank)
+				    (point)))
+			     (end (min (+ beg 60) (line-end-position))))
+			(buffer-substring-no-properties beg end)))))
+	       (format "%3s  %5d %3d %s"
+		       (car mark)
+		       (line-number-at-pos)
+		       (current-column)
+		       file-or-text))))))
+   marks "\n"))
+	       
+	       
+
 (vim:defcmd vim:cmd-show-marks (nonrepeatable (argument marks))
   "Shows all currently defined marks."
   (let ((all-marks (append vim:local-marks-alist vim:global-marks-alist)))
 	    (remq nil (mapcar #'(lambda (x) (and (memq (car x) marks) x)) all-marks))))
 
     (setq all-marks (sort all-marks #'(lambda (x y) (< (car x) (car y)))))
-    (setq all-marks (apply #'concat
-                           (mapcar
-                            #'(lambda (m)
-                                (format "%3c  %5d %3d %s\n"
-                                        (car m)
-                                        (line-number-at-pos (cdr m))
-                                        (save-excursion
-                                          (goto-char (cdr m))
-                                          (current-column))
-                                        (buffer-substring-no-properties
-                                         (save-excursion
-                                           (goto-char (cdr m))
-                                           (line-beginning-position))
-                                         (+ 20
-                                            (save-excursion
-                                              (goto-char (cdr m))
-                                              (line-beginning-position))))))
-                            all-marks)))
+    (setq all-marks (vim:print-mark-list
+		     (mapcar #'(lambda (x)
+				 (cons (char-to-string (car x)) (cdr x)))
+			     all-marks)))
     (let (message-truncate-lines message-log-max)
       (message "%4s %5s %3s %s\n%s" "Mark" "Line" "Col" "File/Text"
                all-marks))))
 
+(vim:defcmd vim:cmd-show-jumps (nonrepeatable)
+  "Shows the current jump-list."
+  (let* ((cnt 0)
+	 (pjumps (mapcar 
+		  #'(lambda (x)
+		      (incf cnt)
+		      (cons (int-to-string cnt) x))
+		  (car vim:jumplist))))
+    (setq cnt -1)
+    (let ((njumps (mapcar
+		   #'(lambda (x)
+		       (incf cnt)
+		       (cons (int-to-string cnt) x))
+		   (cdr vim:jumplist))))
+      (let ((jumps (vim:print-mark-list (append (reverse pjumps) njumps)))
+	    message-truncate-lines message-log-max)
+	(message "%4s %5s %3s %s\n%s" "Jump" "Line" "Col" "File/Text" jumps)))))
+    
+  
+
 (vim:deflocalvar vim:current-macro nil
   "The name of the currently recorded macro.")
 
 
 (vim:omap "'" 'vim:motion-mark-line)
 (vim:omap "`" 'vim:motion-mark)
+(vim:omap (kbd "C-o") 'vim:cmd-prev-jump)
+(vim:omap (kbd "C-i") 'vim:cmd-next-jump)
+(vim:omap [tab] 'indent-for-tab-command)
 
 (vim:omap "iw" 'vim:motion-inner-word)
 (vim:omap "aw" 'vim:motion-outer-word)
 (vim:emap "substitute" 'vim:cmd-substitute)
 (vim:emap "s" "substitute")
 (vim:emap "marks" 'vim:cmd-show-marks)
+(vim:emap "jumps" 'vim:cmd-show-jumps)
+(vim:emap "ju" "jumps")
 (vim:emap "noh" "nohlsearch")
 (vim:emap "nohlsearch" 'vim:cmd-nohighlight)
 

File vim-motions.el

 
 (add-hook 'vim-mode-on-hook
 	  #'(lambda ()
-	      (add-hook 'before-change-functions 'vim:set-change-mark)))
+	      (add-hook 'before-change-functions 'vim:set-change-mark)
+	      (add-hook 'find-file-hook #'vim:add-file-jump)))
 
 (add-hook 'vim-mode-off-hook
 	  #'(lambda ()
-	      (remove-hook 'before-change-functions 'vim:set-change-mark)))
+	      (remove-hook 'before-change-functions 'vim:set-change-mark)
+	      (remove-hook 'find-file-hook #'vim:add-file-jump)))
+
+(defcustom vim:max-jumplist 10
+  "Maximal number of jumps in the jumplist."
+  :group 'vim-motions)
+
+(defvar vim:jumplist '(nil . nil)
+  "The jumplist.
+In contrast to VIM, vim-mode mode has only one jump-list for all
+windows. The reason is that Emacs does not have window-local variables.")
+
+(defun vim:add-file-jump ()
+  "Add a jump into the previous buffer when a new file is
+visited."
+  (let ((b (car (buffer-list))))
+    (with-current-buffer b
+      (vim:add-jump))))
+
+(defun vim:add-jump (&optional pos)
+  "Adds a position or (point) to the jump list."
+  ;; put everything on the before list
+  (dolist (next (cdr vim:jumplist))
+    (push next (car vim:jumplist)))
+  ;; use (point) as default
+  (unless pos (setq pos (point)))
+  ;; filter all old jumps at the same line
+  (let ((line (line-number-at-pos pos))
+	old-jumps new-jumps
+	(size 0))
+    (dolist (j (car vim:jumplist))
+      (if (and (eq (marker-buffer j) (current-buffer))
+	       (= line (line-number-at-pos j)))
+	  (push j old-jumps)
+	(push j new-jumps)
+	(incf size)))
+    
+    ;; remove markers above maximum
+    (while (> size vim:max-jumplist)
+      (push (pop new-jumps) old-jumps))
+    ;; create new marker or reuse old one
+    (let ((m (or (pop old-jumps) (make-marker))))
+      (set-marker m pos)
+      (setcar vim:jumplist (cons m (nreverse new-jumps)))
+      (setcdr vim:jumplist nil))
+    ;; delete old markers
+    (dolist (j old-jumps)
+      (set-marker j nil))))
+      
+
+(vim:defcmd vim:cmd-prev-jump (nonrepeatable count)
+  "Goes to the `count'-th previous jump-position."
+  (unless (car vim:jumplist)
+    (signal 'no-prev-jump (list "No previous jump")))
+  (setq count (or count 1))
+  (while (and (car vim:jumplist)
+	      (> count 0))
+    (if (cdr vim:jumplist)
+	(progn
+	  (push (pop (car vim:jumplist))
+		(cdr vim:jumplist))
+	  (decf count))
+      (vim:add-jump)
+      (push (pop (car vim:jumplist))
+	    (cdr vim:jumplist))))
+  (unless (eq (marker-buffer (cadr vim:jumplist)) 
+	      (current-buffer))
+    (switch-to-buffer (marker-buffer (cadr vim:jumplist))))
+  (goto-char (cadr vim:jumplist)))
+
+
+(vim:defcmd vim:cmd-next-jump (nonrepeatable count)
+  "Goes to the `count'-th previous jump-position."
+  (when (or (null (cdr vim:jumplist))
+	    (null (cddr vim:jumplist)))
+    (signal 'no-next-jump (list "No next jump")))
+  (setq count (or count 1))
+  (while (and (cdr vim:jumplist)
+	      (> count 0))
+    (push (pop (cdr vim:jumplist)) (car vim:jumplist))
+    (decf count))
+  (unless (eq (marker-buffer (cadr vim:jumplist)) 
+	      (current-buffer))
+    (switch-to-buffer (marker-buffer (cadr vim:jumplist))))
+  (goto-char (cadr vim:jumplist)))
+    
 
 (vim:defmotion vim:motion-left (exclusive count)
   "Move the cursor count characters left."
 
 (vim:defmotion vim:motion-window-first-line (linewise count)
   "Moves the cursor to the first line of the window, plus count lines, default zero."
+  (vim:add-jump)
   (move-to-window-line (or count 0))
   (back-to-indentation))
 
 (vim:defmotion vim:motion-window-middle-line (linewise count)
   "Moves the cursor to the beginning of the middle line of the window.  Ignores count."
+  (vim:add-jump)
   (move-to-window-line (/ (window-body-height) 2))
   (back-to-indentation))
 
 (vim:defmotion vim:motion-window-last-line (linewise count)
   "Moves the cursor to the last line of the window, minus count lines, default zero."
+  (vim:add-jump)
   (move-to-window-line (- (window-body-height) (or count 0) 1))
   (back-to-indentation))
 
 
 (vim:defmotion vim:motion-go-to-first-non-blank-beg (linewise count)
   "Moves the cursor to the first non-blank charactor of line count."
+  (vim:add-jump)
   (if count
       (goto-line count)
     (goto-char (point-min)))
 
 (vim:defmotion vim:motion-go-to-first-non-blank-end (linewise count)
   "Moves the cursor to the first non-blank charactor of line count."
+  (vim:add-jump)
   (if count
       (goto-line count)
     (goto-char (point-max)))
 
 (vim:defmotion vim:motion-fwd-sentence (exclusive count)
   "Move the cursor `count' sentences forward."
+  (vim:add-jump)
   (dotimes (i (or count 1))
     (goto-char (min (save-excursion
                       (vim:move-fwd-beg 1 #'vim:boundary-sentence)
 
 (vim:defmotion vim:motion-bwd-sentence (exclusive count)
   "Move the cursor `count' sentences backward."
+  (vim:add-jump)
   (vim:move-bwd-beg (or count 1)
                     (vim:union-boundary #'vim:boundary-sentence #'vim:boundary-paragraph)))
 
 
 (vim:defmotion vim:motion-fwd-paragraph (exclusive count)
   "Move the cursor `count' paragraphs forward."
+  (vim:add-jump)
   (if (eobp) (signal 'end-of-buffer nil)
     (dotimes (i (or count 1))
       (goto-char (or (vim:boundary-paragraph 'fwd) (point-max)))
 
 (vim:defmotion vim:motion-bwd-paragraph (exclusive count)
   "Move the cursor `count' paragraphs backward."
+  (vim:add-jump)
   (if (bobp) (signal 'beginning-of-buffer nil)
     (dotimes (i (or count 1))
       (goto-char (or (vim:boundary-paragraph 'bwd) (point-min)))
 (vim:defmotion vim:motion-jump-item (inclusive)
   "Find the next item in this line after or under the cursor and
 jumps to the corresponding one."
+  (vim:add-jump) 
   (let ((next-open
          (condition-case err
              (1- (scan-lists (point) 1 -1))
 
 (vim:defmotion vim:motion-mark (exclusive (argument:char mark-char))
   "Moves to the position of `mark-char'."
+  (vim:add-jump)
   (goto-char (vim:get-local-mark mark-char)))
 
 (vim:defmotion vim:motion-mark-line (linewise (argument:char mark-char))
   "Moves to the first non-blank char in the line of `mark-char'."
+  (vim:add-jump)
   (goto-char (vim:get-local-mark mark-char))
   (vim:motion-first-non-blank)
   t)

File vim-search.el

 				 ('backward "?"))
 			       nil 'vim:search-history)
 	      (goto-char vim:search-start-point)
+	      (vim:add-jump)
 	      (if vim:search-match-beg
 		  (goto-char vim:search-match-beg)
 		(vim:find-next))
 (vim:defmotion vim:motion-search-next (exclusive count)
   "Goes to the next occurrence."
   (setq vim:search-start-point (point))
+  (vim:add-jump)
   (dotimes (i (or count 1))
     (case vim:search-direction
       ('backward (backward-char))
   (multiple-value-bind (pattern replacement flags) (vim:parse-substitute argument)
     (unless pattern (error "No pattern given."))
     (unless replacement (error "No replacement given."))
+    (vim:add-jump)
     (setq flags (append flags nil))
     (lexical-let* ((replacement replacement)
                    (first-line (if motion (vim:motion-first-line motion) (line-number-at-pos (point))))