Skip to content

Commit

Permalink
Merge pull request #1099 from mrBliss/detect-comma-style
Browse files Browse the repository at this point in the history
Detect comma style
  • Loading branch information
gracjan committed Jan 21, 2016
2 parents 62aafde + 3bdf705 commit f6eb793
Show file tree
Hide file tree
Showing 2 changed files with 148 additions and 56 deletions.
116 changes: 62 additions & 54 deletions haskell-cabal.el
Original file line number Diff line number Diff line change
Expand Up @@ -309,14 +309,6 @@ OTHER-WINDOW use `find-file-other-window'."
:group 'haskell
)

(defcustom haskell-cabal-list-comma-position
'before
"Where to put the comma in lists"
:safe t
:group 'haskell-cabal
:type '(choice (const before)
(const after)))

(defconst haskell-cabal-section-header-regexp "^[[:alnum:]]" )
(defconst haskell-cabal-subsection-header-regexp "^[ \t]*[[:alnum:]]\\w*:")
(defconst haskell-cabal-comment-regexp "^[ \t]*--")
Expand Down Expand Up @@ -582,27 +574,56 @@ string, are not comma separators."
;; inside a comment
(nth 4 ss))))))

(defun haskell-cabal-strip-list-and-detect-style ()
"Strip commas from a comma-separated list.
Detect and return the comma style. The possible options are:
(defun haskell-cabal-strip-list ()
"Strip commas from a comma-separated list."
(goto-char (point-min))
;; split list items on single line
(while (re-search-forward
"\\([^ \t,\n]\\)[ \t]*\\(,\\)[ \t]*\\([^ \t,\n]\\)" nil t)
(when (haskell-cabal-comma-separatorp (match-beginning 2))
(replace-match "\\1\n\\3" nil nil)))
(goto-char (point-min))
(while (re-search-forward "^\\([ \t]*\\),\\([ \t]*\\)" nil t)
(replace-match "" nil nil))
(goto-char (point-min))
(while (re-search-forward ",[ \t]*$" nil t)
(replace-match "" nil nil))
(goto-char (point-min))
(haskell-cabal-each-line (haskell-cabal-chomp-line)))
before: a comma at the start of each line (except the first), e.g.
Foo
, Bar
(defun haskell-cabal-listify ()
"Add commas so that the buffer contains a comma-seperated list"
(cl-case haskell-cabal-list-comma-position
after: a comma at the end of each line (except the last), e.g.
Foo,
Bar
single: everything on a single line, but comma-separated, e.g.
Foo, Bar
nil: no commas, e.g.
Foo Bar
If the styles are mixed, the position of the first comma
determines the style."
(let (comma-style)
;; split list items on single line
(goto-char (point-min))
(while (re-search-forward
"\\([^ \t,\n]\\)[ \t]*\\(,\\)[ \t]*\\([^ \t,\n]\\)" nil t)
(when (haskell-cabal-comma-separatorp (match-beginning 2))
(setq comma-style 'single)
(replace-match "\\1\n\\3" nil nil)))
;; remove commas before
(goto-char (point-min))
(while (re-search-forward "^\\([ \t]*\\),\\([ \t]*\\)" nil t)
(setq comma-style 'before)
(replace-match "" nil nil))
;; remove trailing commas
(goto-char (point-min))
(while (re-search-forward ",[ \t]*$" nil t)
(unless (eq comma-style 'before)
(setq comma-style 'after))
(replace-match "" nil nil))
(goto-char (point-min))

(haskell-cabal-each-line (haskell-cabal-chomp-line))
comma-style))

(defun haskell-cabal-listify (comma-style)
"Add commas so that the buffer contains a comma-separated list.
Respect the COMMA-STYLE, see
`haskell-cabal-strip-list-and-detect-style' for the possible
styles."
(cl-case comma-style
('before
(goto-char (point-min))
(while (haskell-cabal-ignore-line-p) (forward-line))
Expand All @@ -618,38 +639,25 @@ string, are not comma separators."
(forward-line -1)
(end-of-line)
(insert ",")
(beginning-of-line))))))

(defun haskell-cabal-comma-separatedp ()
"Return non-nil when the current buffer contains a comma-separated list.
When the buffer contains at least one comma separator (checked
with `haskell-cabal-comma-separatorp'), the buffer is considered
to be a comma-separated list."
(let ((comma-separatedp nil))
(goto-char (point-min))
(while (and (not comma-separatedp)
(search-forward "," (point-max) t))
(when (haskell-cabal-comma-separatorp (match-beginning 0))
(setq comma-separatedp t))
;; Make sure we don't find the same comma every time
(forward-char 1))
comma-separatedp))

(beginning-of-line))))
('single
(goto-char (point-min))
(while (not (eobp))
(end-of-line)
(unless (eobp)
(insert ", ")
(delete-char 1)
(just-one-space))))))

(defmacro haskell-cabal-with-cs-list (&rest funs)
"Format the buffer so that each line contains a list element.
Keep the lines comma-separated if and only if they were in the
first place."
(let ((comma-separatedp (make-symbol "comma-separatedp")))
`(let ((,comma-separatedp
Respect the comma style."
(let ((comma-style (make-symbol "comma-style")))
`(let ((,comma-style
(save-excursion
(prog1
(haskell-cabal-comma-separatedp)
(haskell-cabal-strip-list)))))
(haskell-cabal-strip-list-and-detect-style))))
(unwind-protect (progn ,@funs)
;; Only reinsert commas when it already was comma-separated.
(when ,comma-separatedp
(haskell-cabal-listify))))))
(haskell-cabal-listify ,comma-style)))))


(defun haskell-cabal-sort-lines-key-fun ()
Expand Down
88 changes: 86 additions & 2 deletions tests/haskell-cabal-tests.el
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,42 @@
(haskell-cabal-previous-subsection)
(haskell-cabal-previous-section))))

(ert-deftest haskell-cabal-subsection-arrange-lines-keep-commas ()
(ert-deftest haskell-cabal-subsection-arrange-lines-keep-trailing-commas ()
(should (with-temp-buffer
(insert "Executable bin-1
Main-Is: TestParsing.hs
Build-Depends: base,
bytestring,
filepath,
directory,
text
Ghc-Options: -O -Wall
")
(haskell-cabal-mode)
(goto-char (point-min))
(search-forward "Build-Depends:")
(haskell-cabal-subsection-arrange-lines)
(string= (buffer-string)
"Executable bin-1
Main-Is: TestParsing.hs
Build-Depends: base,
bytestring,
directory,
filepath,
text
Ghc-Options: -O -Wall
"))))

(ert-deftest haskell-cabal-subsection-arrange-lines-keep-commas-before ()
(should (with-temp-buffer
(insert "Executable bin-1
Main-Is: TestParsing.hs
Build-Depends: base
, bytestring
, filepath
, directory
, text
Ghc-Options: -O -Wall
")
(haskell-cabal-mode)
(goto-char (point-min))
Expand Down Expand Up @@ -96,6 +122,29 @@
Some.Other.Other.Module
"))))

(ert-deftest haskell-cabal-subsection-arrange-lines-mixed-styles ()
(should (with-temp-buffer
(insert "Executable bin-1
Main-Is: TestParsing.hs
Build-Depends: base
, bytestring,
filepath, directory, text
Ghc-Options: -O -Wall
")
(haskell-cabal-mode)
(goto-char (point-min))
(search-forward "Build-Depends:")
(haskell-cabal-subsection-arrange-lines)
(string= (buffer-string)
"Executable bin-1
Main-Is: TestParsing.hs
Build-Depends: base
, bytestring
, directory
, filepath
, text
Ghc-Options: -O -Wall
"))))

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

(ert-deftest haskell-cabal-subsection-arrange-lines-commas-quoted-comma ()
(ert-deftest haskell-cabal-subsection-arrange-lines-single-line-quoted-comma ()
(should (with-temp-buffer
(insert "Executable bin-1
Main-Is: TestParsing.hs
GHC-Options: -Wall,-fprof-auto \"foo, bar\"
")
(haskell-cabal-mode)
(goto-char (point-min))
(search-forward "GHC-Options:")
(haskell-cabal-subsection-arrange-lines)
(string= (buffer-string)
"Executable bin-1
Main-Is: TestParsing.hs
GHC-Options: -Wall, -fprof-auto \"foo, bar\"
"))))

(ert-deftest haskell-cabal-subsection-arrange-lines-trailing-commas-quoted-comma ()
(should (with-temp-buffer
(insert "Executable bin-1
Main-Is: TestParsing.hs
GHC-Options: -Wall,
-fprof-auto \"foo, bar\"
")
(haskell-cabal-mode)
(goto-char (point-min))
(search-forward "GHC-Options:")
(haskell-cabal-subsection-arrange-lines)
(string= (buffer-string)
"Executable bin-1
Main-Is: TestParsing.hs
GHC-Options: -Wall,
-fprof-auto \"foo, bar\"
"))))

(ert-deftest haskell-cabal-subsection-arrange-lines-commas-before-quoted-comma ()
(should (with-temp-buffer
(insert "Executable bin-1
Main-Is: TestParsing.hs
GHC-Options: -Wall
, -fprof-auto \"foo, bar\"
")
(haskell-cabal-mode)
(goto-char (point-min))
Expand Down

0 comments on commit f6eb793

Please sign in to comment.