Skip to content

Commit f6eb793

Browse files
committed
Merge pull request #1099 from mrBliss/detect-comma-style
Detect comma style
2 parents 62aafde + 3bdf705 commit f6eb793

File tree

2 files changed

+148
-56
lines changed

2 files changed

+148
-56
lines changed

haskell-cabal.el

Lines changed: 62 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -309,14 +309,6 @@ OTHER-WINDOW use `find-file-other-window'."
309309
:group 'haskell
310310
)
311311

312-
(defcustom haskell-cabal-list-comma-position
313-
'before
314-
"Where to put the comma in lists"
315-
:safe t
316-
:group 'haskell-cabal
317-
:type '(choice (const before)
318-
(const after)))
319-
320312
(defconst haskell-cabal-section-header-regexp "^[[:alnum:]]" )
321313
(defconst haskell-cabal-subsection-header-regexp "^[ \t]*[[:alnum:]]\\w*:")
322314
(defconst haskell-cabal-comment-regexp "^[ \t]*--")
@@ -582,27 +574,56 @@ string, are not comma separators."
582574
;; inside a comment
583575
(nth 4 ss))))))
584576

577+
(defun haskell-cabal-strip-list-and-detect-style ()
578+
"Strip commas from a comma-separated list.
579+
Detect and return the comma style. The possible options are:
585580
586-
(defun haskell-cabal-strip-list ()
587-
"Strip commas from a comma-separated list."
588-
(goto-char (point-min))
589-
;; split list items on single line
590-
(while (re-search-forward
591-
"\\([^ \t,\n]\\)[ \t]*\\(,\\)[ \t]*\\([^ \t,\n]\\)" nil t)
592-
(when (haskell-cabal-comma-separatorp (match-beginning 2))
593-
(replace-match "\\1\n\\3" nil nil)))
594-
(goto-char (point-min))
595-
(while (re-search-forward "^\\([ \t]*\\),\\([ \t]*\\)" nil t)
596-
(replace-match "" nil nil))
597-
(goto-char (point-min))
598-
(while (re-search-forward ",[ \t]*$" nil t)
599-
(replace-match "" nil nil))
600-
(goto-char (point-min))
601-
(haskell-cabal-each-line (haskell-cabal-chomp-line)))
581+
before: a comma at the start of each line (except the first), e.g.
582+
Foo
583+
, Bar
602584
603-
(defun haskell-cabal-listify ()
604-
"Add commas so that the buffer contains a comma-seperated list"
605-
(cl-case haskell-cabal-list-comma-position
585+
after: a comma at the end of each line (except the last), e.g.
586+
Foo,
587+
Bar
588+
589+
single: everything on a single line, but comma-separated, e.g.
590+
Foo, Bar
591+
592+
nil: no commas, e.g.
593+
Foo Bar
594+
595+
If the styles are mixed, the position of the first comma
596+
determines the style."
597+
(let (comma-style)
598+
;; split list items on single line
599+
(goto-char (point-min))
600+
(while (re-search-forward
601+
"\\([^ \t,\n]\\)[ \t]*\\(,\\)[ \t]*\\([^ \t,\n]\\)" nil t)
602+
(when (haskell-cabal-comma-separatorp (match-beginning 2))
603+
(setq comma-style 'single)
604+
(replace-match "\\1\n\\3" nil nil)))
605+
;; remove commas before
606+
(goto-char (point-min))
607+
(while (re-search-forward "^\\([ \t]*\\),\\([ \t]*\\)" nil t)
608+
(setq comma-style 'before)
609+
(replace-match "" nil nil))
610+
;; remove trailing commas
611+
(goto-char (point-min))
612+
(while (re-search-forward ",[ \t]*$" nil t)
613+
(unless (eq comma-style 'before)
614+
(setq comma-style 'after))
615+
(replace-match "" nil nil))
616+
(goto-char (point-min))
617+
618+
(haskell-cabal-each-line (haskell-cabal-chomp-line))
619+
comma-style))
620+
621+
(defun haskell-cabal-listify (comma-style)
622+
"Add commas so that the buffer contains a comma-separated list.
623+
Respect the COMMA-STYLE, see
624+
`haskell-cabal-strip-list-and-detect-style' for the possible
625+
styles."
626+
(cl-case comma-style
606627
('before
607628
(goto-char (point-min))
608629
(while (haskell-cabal-ignore-line-p) (forward-line))
@@ -618,38 +639,25 @@ string, are not comma separators."
618639
(forward-line -1)
619640
(end-of-line)
620641
(insert ",")
621-
(beginning-of-line))))))
622-
623-
(defun haskell-cabal-comma-separatedp ()
624-
"Return non-nil when the current buffer contains a comma-separated list.
625-
When the buffer contains at least one comma separator (checked
626-
with `haskell-cabal-comma-separatorp'), the buffer is considered
627-
to be a comma-separated list."
628-
(let ((comma-separatedp nil))
629-
(goto-char (point-min))
630-
(while (and (not comma-separatedp)
631-
(search-forward "," (point-max) t))
632-
(when (haskell-cabal-comma-separatorp (match-beginning 0))
633-
(setq comma-separatedp t))
634-
;; Make sure we don't find the same comma every time
635-
(forward-char 1))
636-
comma-separatedp))
637-
642+
(beginning-of-line))))
643+
('single
644+
(goto-char (point-min))
645+
(while (not (eobp))
646+
(end-of-line)
647+
(unless (eobp)
648+
(insert ", ")
649+
(delete-char 1)
650+
(just-one-space))))))
638651

639652
(defmacro haskell-cabal-with-cs-list (&rest funs)
640653
"Format the buffer so that each line contains a list element.
641-
Keep the lines comma-separated if and only if they were in the
642-
first place."
643-
(let ((comma-separatedp (make-symbol "comma-separatedp")))
644-
`(let ((,comma-separatedp
654+
Respect the comma style."
655+
(let ((comma-style (make-symbol "comma-style")))
656+
`(let ((,comma-style
645657
(save-excursion
646-
(prog1
647-
(haskell-cabal-comma-separatedp)
648-
(haskell-cabal-strip-list)))))
658+
(haskell-cabal-strip-list-and-detect-style))))
649659
(unwind-protect (progn ,@funs)
650-
;; Only reinsert commas when it already was comma-separated.
651-
(when ,comma-separatedp
652-
(haskell-cabal-listify))))))
660+
(haskell-cabal-listify ,comma-style)))))
653661

654662

655663
(defun haskell-cabal-sort-lines-key-fun ()

tests/haskell-cabal-tests.el

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,42 @@
5050
(haskell-cabal-previous-subsection)
5151
(haskell-cabal-previous-section))))
5252

53-
(ert-deftest haskell-cabal-subsection-arrange-lines-keep-commas ()
53+
(ert-deftest haskell-cabal-subsection-arrange-lines-keep-trailing-commas ()
5454
(should (with-temp-buffer
5555
(insert "Executable bin-1
5656
Main-Is: TestParsing.hs
57+
Build-Depends: base,
58+
bytestring,
59+
filepath,
60+
directory,
61+
text
62+
Ghc-Options: -O -Wall
63+
")
64+
(haskell-cabal-mode)
65+
(goto-char (point-min))
66+
(search-forward "Build-Depends:")
67+
(haskell-cabal-subsection-arrange-lines)
68+
(string= (buffer-string)
69+
"Executable bin-1
70+
Main-Is: TestParsing.hs
5771
Build-Depends: base,
5872
bytestring,
5973
directory,
6074
filepath,
6175
text
6276
Ghc-Options: -O -Wall
77+
"))))
78+
79+
(ert-deftest haskell-cabal-subsection-arrange-lines-keep-commas-before ()
80+
(should (with-temp-buffer
81+
(insert "Executable bin-1
82+
Main-Is: TestParsing.hs
83+
Build-Depends: base
84+
, bytestring
85+
, filepath
86+
, directory
87+
, text
88+
Ghc-Options: -O -Wall
6389
")
6490
(haskell-cabal-mode)
6591
(goto-char (point-min))
@@ -96,6 +122,29 @@
96122
Some.Other.Other.Module
97123
"))))
98124

125+
(ert-deftest haskell-cabal-subsection-arrange-lines-mixed-styles ()
126+
(should (with-temp-buffer
127+
(insert "Executable bin-1
128+
Main-Is: TestParsing.hs
129+
Build-Depends: base
130+
, bytestring,
131+
filepath, directory, text
132+
Ghc-Options: -O -Wall
133+
")
134+
(haskell-cabal-mode)
135+
(goto-char (point-min))
136+
(search-forward "Build-Depends:")
137+
(haskell-cabal-subsection-arrange-lines)
138+
(string= (buffer-string)
139+
"Executable bin-1
140+
Main-Is: TestParsing.hs
141+
Build-Depends: base
142+
, bytestring
143+
, directory
144+
, filepath
145+
, text
146+
Ghc-Options: -O -Wall
147+
"))))
99148

100149
(ert-deftest haskell-cabal-subsection-arrange-lines-quoted-items ()
101150
(should (with-temp-buffer
@@ -129,11 +178,46 @@
129178
GHC-Options: -Wall -fprof-auto \"foo, bar\"
130179
"))))
131180

132-
(ert-deftest haskell-cabal-subsection-arrange-lines-commas-quoted-comma ()
181+
(ert-deftest haskell-cabal-subsection-arrange-lines-single-line-quoted-comma ()
133182
(should (with-temp-buffer
134183
(insert "Executable bin-1
135184
Main-Is: TestParsing.hs
185+
GHC-Options: -Wall,-fprof-auto \"foo, bar\"
186+
")
187+
(haskell-cabal-mode)
188+
(goto-char (point-min))
189+
(search-forward "GHC-Options:")
190+
(haskell-cabal-subsection-arrange-lines)
191+
(string= (buffer-string)
192+
"Executable bin-1
193+
Main-Is: TestParsing.hs
136194
GHC-Options: -Wall, -fprof-auto \"foo, bar\"
195+
"))))
196+
197+
(ert-deftest haskell-cabal-subsection-arrange-lines-trailing-commas-quoted-comma ()
198+
(should (with-temp-buffer
199+
(insert "Executable bin-1
200+
Main-Is: TestParsing.hs
201+
GHC-Options: -Wall,
202+
-fprof-auto \"foo, bar\"
203+
")
204+
(haskell-cabal-mode)
205+
(goto-char (point-min))
206+
(search-forward "GHC-Options:")
207+
(haskell-cabal-subsection-arrange-lines)
208+
(string= (buffer-string)
209+
"Executable bin-1
210+
Main-Is: TestParsing.hs
211+
GHC-Options: -Wall,
212+
-fprof-auto \"foo, bar\"
213+
"))))
214+
215+
(ert-deftest haskell-cabal-subsection-arrange-lines-commas-before-quoted-comma ()
216+
(should (with-temp-buffer
217+
(insert "Executable bin-1
218+
Main-Is: TestParsing.hs
219+
GHC-Options: -Wall
220+
, -fprof-auto \"foo, bar\"
137221
")
138222
(haskell-cabal-mode)
139223
(goto-char (point-min))

0 commit comments

Comments
 (0)