Skip to content

Commit bd984c9

Browse files
Add prettier-js-prettify-region (#92)
* Add prettier-js-prettify-region * Add test for prettier-js-prettify-region * Use new function name * Add menu item to format an active region * Add guard to ensure the region is active before formatting
1 parent db508bd commit bd984c9

File tree

4 files changed

+100
-26
lines changed

4 files changed

+100
-26
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[![MELPA](http://melpa.org/packages/prettier-js-badge.svg)](http://melpa.org/#/prettier-js) [![CI](https://github.com/prettier/prettier-emacs/actions/workflows/test.yml/badge.svg)](https://github.com/prettier/prettier-emacs/actions/workflows/test.yml)
44

5-
This Emacs package provides a function, `prettier-js`, which formats the current buffer using [Prettier](https://github.com/prettier/prettier). It also exports a minor mode, `prettier-js-mode`, which calls `prettier-js` on save.
5+
This Emacs package provides a function, `prettier-js-prettify`, which formats the current buffer using [Prettier](https://github.com/prettier/prettier). It also exports a minor mode, `prettier-js-mode`, which calls `prettier-js-prettify` on save.
66

77
## Configuration
88

fixtures/partial-clean.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
function messy(a,b)
2+
{
3+
return a+b
4+
+100;
5+
}
6+
7+
const obj = {
8+
foo: "bar",
9+
baz: 42,
10+
qux: [1, 2, 3],
11+
};
12+
13+
// This is a messy JavaScript file
14+
if(true){console.log("hello world")}

prettier-js-test.el

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
;; Visit the temp file
5252
(with-current-buffer (find-file-noselect temp-file)
5353
;; Format the buffer
54-
(prettier-js)
54+
(prettier-js-prettify)
5555

5656
;; Get the expected clean content
5757
(let ((expected-content
@@ -88,7 +88,7 @@
8888
;; Visit the messy file
8989
(with-current-buffer (find-file-noselect temp-src-file)
9090
;; Format the buffer using node_modules/.bin/prettier
91-
(prettier-js)
91+
(prettier-js-prettify)
9292

9393
;; Get the expected clean content
9494
(let ((expected-content
@@ -122,7 +122,7 @@
122122

123123
;; Switch to the indirect buffer and format it
124124
(with-current-buffer indirect-buffer
125-
(prettier-js)
125+
(prettier-js-prettify)
126126

127127
;; Get the expected clean content
128128
(let ((expected-content
@@ -149,7 +149,7 @@
149149
(js-mode)
150150

151151
;; Verify that the appropriate error is signaled with the correct message
152-
(let ((err (should-error (prettier-js) :type 'user-error)))
152+
(let ((err (should-error (prettier-js-prettify) :type 'user-error)))
153153
(should (string-match-p "Buffer .* is not visiting a file" (cadr err))))))
154154

155155
(ert-deftest prettier-js-test-executable-not-found ()
@@ -166,7 +166,7 @@
166166
;; Visit the temp file
167167
(with-current-buffer (find-file-noselect temp-file)
168168
;; Verify that the appropriate error is signaled with the correct message
169-
(let ((err (should-error (prettier-js) :type 'user-error)))
169+
(let ((err (should-error (prettier-js-prettify) :type 'user-error)))
170170
(should (string= "Could not find prettier executable" (cadr err))))
171171
(kill-buffer)))
172172

@@ -189,7 +189,7 @@
189189
;; Visit the temp file
190190
(with-current-buffer (find-file-noselect temp-file)
191191
;; Verify that the appropriate error is signaled with the correct message
192-
(let ((err (should-error (prettier-js) :type 'user-error)))
192+
(let ((err (should-error (prettier-js-prettify) :type 'user-error)))
193193
(should (string= "Could not find node_modules/.bin/prettier executable" (cadr err))))
194194
(kill-buffer)))
195195

@@ -210,7 +210,7 @@
210210
;; Visit the temp file
211211
(with-current-buffer (find-file-noselect temp-file)
212212
;; Verify that the appropriate error is signaled with the correct message
213-
(let ((err (should-error (prettier-js) :type 'user-error)))
213+
(let ((err (should-error (prettier-js-prettify) :type 'user-error)))
214214
(should (string= "Could not find diff executable" (cadr err))))
215215
(kill-buffer)))
216216

@@ -238,7 +238,7 @@
238238
;; Visit the temp file
239239
(with-current-buffer (find-file-noselect temp-file)
240240
;; Verify that the appropriate error is signaled with the correct message
241-
(let ((err (should-error (prettier-js) :type 'user-error)))
241+
(let ((err (should-error (prettier-js-prettify) :type 'user-error)))
242242
(should (string= "Error calling diff; is GNU diff on your path?" (cadr err))))
243243
(kill-buffer))))
244244

@@ -262,7 +262,7 @@
262262
;; Visit the temp file
263263
(with-current-buffer (find-file-noselect temp-file)
264264
;; Run prettier-js which should display the error
265-
(prettier-js)
265+
(prettier-js-prettify)
266266

267267
;; Check that the error buffer exists and contains the error message
268268
(let ((error-buffer (get-buffer "*prettier errors*")))
@@ -295,7 +295,7 @@
295295
;; Visit the temp file
296296
(with-current-buffer (find-file-noselect temp-file)
297297
;; Run prettier-js which should display the error
298-
(prettier-js)
298+
(prettier-js-prettify)
299299

300300
;; Check that the error buffer exists and contains the error message
301301
(let ((error-buffer (get-buffer "*prettier errors*")))
@@ -318,5 +318,48 @@
318318
(when (file-exists-p temp-dir)
319319
(delete-directory temp-dir t)))))
320320

321+
(ert-deftest prettier-js-test-prettify-region ()
322+
"Test that prettier-js-prettify-region correctly formats a region of JavaScript code."
323+
(let* ((dirty-file (expand-file-name "fixtures/dirty.js"))
324+
(partial-clean-file (expand-file-name "fixtures/partial-clean.js"))
325+
(temp-file (make-temp-file "prettier-test-" nil ".js")))
326+
(unwind-protect
327+
(progn
328+
;; Copy dirty content to temp file
329+
(copy-file dirty-file temp-file t)
330+
331+
;; Visit the temp file
332+
(with-current-buffer (find-file-noselect temp-file)
333+
;; Find the object declaration and format just that region
334+
(goto-char (point-min))
335+
(search-forward "const obj = {")
336+
(beginning-of-line)
337+
(let ((start (point))
338+
(end (progn
339+
(search-forward "};")
340+
(point))))
341+
342+
;; Set the region and format it
343+
(push-mark start)
344+
(goto-char end)
345+
(activate-mark)
346+
(prettier-js-prettify-region)
347+
348+
;; Get the expected partial clean content
349+
(let ((expected-content
350+
(with-temp-buffer
351+
(insert-file-contents partial-clean-file)
352+
(buffer-string)))
353+
(actual-content (buffer-string)))
354+
355+
;; Compare the formatted content with the expected partial clean content
356+
(should (string= actual-content expected-content))))
357+
358+
(kill-buffer)))
359+
360+
;; Clean up temp file
361+
(when (file-exists-p temp-file)
362+
(delete-file temp-file)))))
363+
321364
(provide 'prettier-js-test)
322365
;;; prettier-js-test.el ends here

prettier-js.el

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ When non-nil, contains the error message to display.")
103103
(goto-char (point-min))
104104
(forward-line (1- line)))
105105

106-
(defun prettier-js--apply-rcs-patch (patch-buffer)
106+
(defun prettier-js--apply-rcs-patch (patch-buffer &optional start)
107107
"Apply an RCS-formatted diff from PATCH-BUFFER to the current buffer."
108108
(let ((target-buffer (current-buffer))
109109
;; Relative offset between buffer line numbers and line numbers
@@ -116,7 +116,7 @@ When non-nil, contains the error message to display.")
116116
;; Appending lines decrements the offset (possibly making it
117117
;; negative), deleting lines increments it. This order
118118
;; simplifies the forward-line invocations.
119-
(line-offset 0))
119+
(line-offset (if start (* (- (line-number-at-pos start) 1) -1) 0)))
120120
(save-excursion
121121
(with-current-buffer patch-buffer
122122
(goto-char (point-min))
@@ -249,17 +249,17 @@ Returns the exit code from prettier."
249249
prettier-cmd bufferfile (list (list :file outputfile) errorfile)
250250
nil (append prettier-js-args width-args (list "--stdin-filepath" file-path)))))
251251

252-
(defun prettier-js--call-diff (outputfile patchbuf)
252+
(defun prettier-js--call-diff (outputfile patchbuf &optional start end)
253253
"Call diff command to generate patch between current buffer and OUTPUTFILE.
254254
PATCHBUF is the buffer where the diff output will be written."
255-
(let ((diff-cmd (prettier-js--get-diff-command)))
256-
(call-process-region (point-min) (point-max) diff-cmd nil patchbuf nil
255+
(let ((start-point (or start (point-min)))
256+
(end-point (or end (point-max)))
257+
(diff-cmd (prettier-js--get-diff-command)))
258+
(call-process-region start-point end-point diff-cmd nil patchbuf nil
257259
"-n" "--strip-trailing-cr" "-" outputfile)))
258260

259-
;;;###autoload
260-
(defun prettier-js ()
261-
"Format the current buffer according to the prettier tool."
262-
(interactive)
261+
(defun prettier-js--prettify (&optional start end)
262+
"Format content in the current buffer from START to END."
263263
(let* ((file-path
264264
(or (prettier-js--file-path)
265265
(user-error "Buffer `%s' is not visiting a file" (buffer-name))))
@@ -280,7 +280,7 @@ PATCHBUF is the buffer where the diff output will be written."
280280
(unwind-protect
281281
(save-restriction
282282
(widen)
283-
(write-region nil nil bufferfile)
283+
(write-region start end bufferfile)
284284
(if errbuf
285285
(with-current-buffer errbuf
286286
(setq buffer-read-only nil)
@@ -294,9 +294,9 @@ PATCHBUF is the buffer where the diff output will be written."
294294
;; 1 - The files are different (differences found).
295295
;; 2 - Trouble occurred (e.g. invalid options).
296296
;; 0/1 = success, 2 = problem
297-
(if (<= (prettier-js--call-diff outputfile patchbuf) 1)
297+
(if (<= (prettier-js--call-diff outputfile patchbuf start end) 1)
298298
(progn
299-
(prettier-js--apply-rcs-patch patchbuf)
299+
(prettier-js--apply-rcs-patch patchbuf start)
300300
(message "Applied prettier with args `%s'" prettier-js-args)
301301
(if errbuf (prettier-js--kill-error-buffer errbuf)))
302302
(setq prettier-js-error-state "Diff command had an issue")
@@ -309,6 +309,22 @@ PATCHBUF is the buffer where the diff output will be written."
309309
(delete-file bufferfile)
310310
(delete-file outputfile))))
311311

312+
;;;###autoload
313+
(defalias 'prettier-js 'prettier-js-prettify)
314+
315+
;;;###autoload
316+
(defun prettier-js-prettify ()
317+
"Format the current buffer according to the prettier tool."
318+
(interactive)
319+
(prettier-js--prettify))
320+
321+
;;;###autoload
322+
(defun prettier-js-prettify-region ()
323+
"Format the current region according to the prettier tool."
324+
(interactive)
325+
(when (region-active-p)
326+
(prettier-js--prettify (region-beginning) (region-end))))
327+
312328
(defvar prettier-js-mode-menu-map
313329
(let ((map (make-sparse-keymap "Prettier")))
314330
map)
@@ -344,7 +360,8 @@ Adds an error item at the top of the menu if there is an error state."
344360
(easy-menu-define prettier-js-mode-menu prettier-js-mode-menu-map
345361
"Menu for Prettier mode"
346362
'("Prettier" :filter prettier-js--menu-filter
347-
["Format buffer" prettier-js t]
363+
["Format buffer" prettier-js-prettify t]
364+
["Format region" prettier-js-prettify-region (region-active-p)]
348365
"---"
349366
["Turn off minor mode" prettier-js-mode :visible prettier-js-mode]
350367
["Help for minor mode" (describe-function 'prettier-js-mode) t]))
@@ -356,8 +373,8 @@ Adds an error item at the top of the menu if there is an error state."
356373
:global nil
357374
:keymap prettier-js-mode-menu-map
358375
(if prettier-js-mode
359-
(add-hook 'before-save-hook 'prettier-js nil 'local)
360-
(remove-hook 'before-save-hook 'prettier-js 'local)))
376+
(add-hook 'before-save-hook 'prettier-js-prettify nil 'local)
377+
(remove-hook 'before-save-hook 'prettier-js-prettify 'local)))
361378

362379
(provide 'prettier-js)
363380
;;; prettier-js.el ends here

0 commit comments

Comments
 (0)