File: crq.el

package info (click to toggle)
chromium 138.0.7204.157-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 6,071,864 kB
  • sloc: cpp: 34,936,859; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,967; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (157 lines) | stat: -rw-r--r-- 5,076 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
;;; TODO(plundblad):
;;; - Allow adding comments outside of the diff directly from a target
;;;   file.
;;; - Hide hunks with only imports etc.
;;; - Hide whitespace-only changes.
;;; - Fix path depotization to not assume google3 or eng.

;;; This elisp file adds a mode based on diff-mode to add comments to specific
;;; lines of files in the diff.  It is intended to be used with files produced
;;; by g4 diff (it requires the target files to exist).  In a diff file,
;;; enable this mode with crq-mode.  You can also run g4 diff
;;; and enable crq mode with the command crq-review.
;;; Then press Enter on any line in the diff
;;; to open up a comment at the end of the file annotated with filename and
;;; line number.
;;;
;;; When done, enter any overall comments right below the "=== COMMENTS ==="
;;; line.  The first line can be "LGTM" or "FYI" to add a vote.  Then
;;; use the command crq-publish to upload and publish your comments to
;;; critique.

(require 'diff-mode)
(require 'p4-google)

(defconst crq-comments-header "=== COMMENTS ===\n")
(defconst crq-file-separator
  "========================================================================\n")
(defconst crq-file-format
  (concat crq-file-separator "File %s\n"))
(defconst crq-line-format
  "------------------------------------\nLine %d: %s\n\n")
(defconst mch-program
  (expand-file-name "mph.py"
                    (file-name-directory load-file-name)))

(defconst download-program
  (expand-file-name "download_issue"
                    (file-name-directory load-file-name)))


(define-derived-mode crq-mode diff-mode "Crq"
  "Special diff mode for code reviews
\\{crq-mode-map}"
  (crq-ensure-header)
  (crq-install-diff-map))

(define-key crq-mode-map "\C-c\C-p" 'crq-publish)
(defun crq-review (change-list-number)
  "Run download script asynchronously on CHANGE-LIST-NUMBER (a string) and
activate crq-mode in the resulting buffer."
  (interactive (list (read-change-list)))
  (let ((process
         (start-process "Gerrit Review" "gerrit-review" download-program change-list-number)))
    (set-process-sentinel process 'crq-diff-sentinel)
    (message "Gerrit download...")))

; TODO(plundblad): Perhaps run the python script asynchronously.
(defun crq-publish (arg)
  "Publishes the comments in the current buffer to critique."
  (interactive "P")
  (goto-char (point-max))
  (let ((result (call-process-region (point-min) (point-max) mch-program nil
                                     (current-buffer) t
                                     "/dev/stdin")))
    (if (not (zerop result))
        (progn
          (message "Error running mch"))))
  t)

(defun crq-comment ()
  (interactive)
  (let* ((loc (diff-find-source-location nil t))
	 (buf (nth 0 loc))
	 (pos (nth 2 loc))
	 (src (nth 3 loc))
	 (offset (+ (car pos) (cdr src)))
	 (line
	  (with-current-buffer buf
	    (save-excursion
	      (goto-char offset)
	      (thing-at-point 'line))))
	 (filename (buffer-file-name buf))
	 (lineno
	  (with-current-buffer buf
            (save-excursion
              (goto-char offset)
              ; count-lines counts the current line if point is not
              ; at the beginning of the line.
              (beginning-of-line)
              (1+ (count-lines (point-min) (point)))))))
    (crq-ensure-header)
    (crq-add-comment
     (file-relative-name filename) lineno line)))

(defun crq-ensure-header ()
  (save-excursion
    (goto-char (point-min))
    (if (not (search-forward crq-comments-header nil t))
      (progn
	(goto-char (point-max))
	(insert ?\n crq-comments-header
		?\n crq-file-separator)))))

(defvar crq-diff-map
  (let ((map (make-sparse-keymap)))
    (define-key map "\r" 'crq-comment)
    map))

(defun crq-install-diff-map ()
  (let* ((end
	 (save-excursion
	   (goto-char (point-max))
	   (unless (search-backward crq-comments-header nil t)
	     (error "No comment header"))
	   (point)))
	 (overlay (make-overlay (point-min) end)))
    (overlay-put overlay 'keymap crq-diff-map)))


(defun crq-fix-filename (fullname)
  (cond
   ((string-match "/\\(google3\\|eng\\)/.*$" fullname)
    (concat "//depot" (match-string 0 fullname)))
   ((string-match "/\\(a\\|b\\)/.*$" fullname)
    (substring (match-string 0 fullname) 3))
   (t fullname)))

(defun crq-trim-line (line)
  (if (string-match "^\\s-*\\(.*?\\)\\s-*$" line)
      (match-string 1 line)
    line))

(defun crq-add-comment (filename lineno text)
  (push-mark)
  (goto-char (point-max))
  (forward-line -1)
  (beginning-of-line)
  (unless (looking-at crq-file-separator)
    (error "Garbage at the end of the file"))
  (insert (format crq-file-format filename))
  (insert (format crq-line-format lineno
		  (crq-trim-line text)))
  (forward-line -1))

(defun crq-diff-sentinel (process event)
  (if (string= event "finished\n")
      (progn
        (message "Downloaded from gerrit")
        (pop-to-buffer (process-buffer process))
        (crq-mode)
        (goto-char (point-min))
        (search-forward "\t" nil t))
    (progn
      (message "g4 diff %s" event)
      (ding))))

(provide 'crq)