Skip to content

Commit f3afdc0

Browse files
committed
initial add
I've promoted these out of their original Makefile-oriented repos into their own cabal package.
0 parents  commit f3afdc0

File tree

6 files changed

+436
-0
lines changed

6 files changed

+436
-0
lines changed

.gitignore

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
tags
2+
/dist/
3+
/dist-newstyle/
4+
/cabal-dev/
5+
*.o
6+
*.hi
7+
*.chi
8+
*.chs.h
9+
.virtualenv
10+
.hsenv
11+
.cabal-sandbox/
12+
cabal.sandbox.config
13+
cabal.config
14+
*~
15+
*.swp

LICENSE

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
Copyright Evan Laforge 2011
2+
3+
All rights reserved.
4+
5+
Redistribution and use in source and binary forms, with or without
6+
modification, are permitted provided that the following conditions are met:
7+
8+
* Redistributions of source code must retain the above copyright
9+
notice, this list of conditions and the following disclaimer.
10+
11+
* Redistributions in binary form must reproduce the above
12+
copyright notice, this list of conditions and the following
13+
disclaimer in the documentation and/or other materials provided
14+
with the distribution.
15+
16+
* Neither the name of Evan Laforge nor the names of other
17+
contributors may be used to endorse or promote products derived
18+
from this software without specific prior written permission.
19+
20+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Some small source code manipulation tools I use with vim. They're external
2+
filters, though, so if you use acme instead of vim, they should work fine there
3+
too.
4+
5+
- cmt - Comment and uncomment code.
6+
7+
- string-literal - Toggle between raw text and list of lines or Haskell
8+
backslash string gap style.

src-util.cabal

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: src-util
2+
version: 0.1
3+
cabal-version: >= 1.8
4+
build-type: Simple
5+
synopsis: source code editing utilities
6+
description:
7+
Collection of small utilities to manipulate source code.
8+
9+
category: Haskell, Development
10+
license: BSD3
11+
license-file: LICENSE
12+
author: Evan Laforge
13+
maintainer: Evan Laforge <qdunkan@gmail.com>
14+
stability: stable
15+
tested-with:
16+
GHC ==7.8.4, GHC ==7.10.3, GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.1
17+
data-files: README.md
18+
19+
homepage: https://github.com/elaforge/src-util
20+
source-repository head
21+
type: git
22+
location: git://github.com/elaforge/src-util.git
23+
24+
executable string-literal
25+
main-is: src/StringLiteral.hs
26+
build-depends:
27+
base >= 3 && < 5,
28+
text
29+
ghc-options:
30+
-Wall -fno-warn-name-shadowing
31+
32+
executable cmt
33+
main-is: src/Cmt.hs
34+
build-depends:
35+
base >= 3 && < 5,
36+
text
37+
ghc-options:
38+
-Wall -fno-warn-name-shadowing

src/Cmt.hs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
{-# LANGUAGE OverloadedStrings #-}
2+
import qualified Data.Char as Char
3+
import qualified Data.List as List
4+
import Data.Monoid ((<>))
5+
import qualified Data.Text as Text
6+
import Data.Text (Text)
7+
import qualified Data.Text.IO as Text.IO
8+
9+
import qualified System.Environment
10+
import qualified System.Exit
11+
12+
13+
type Cmt = Text
14+
15+
usage :: String
16+
usage = "usage: cmt cmt_char"
17+
18+
main :: IO ()
19+
main = do
20+
args <- System.Environment.getArgs
21+
case args of
22+
[cmt] -> do
23+
Text.IO.interact (ignoreBlankLines (cmtOrUncmt (Text.pack cmt)))
24+
_ -> do
25+
putStrLn usage
26+
System.Exit.exitFailure
27+
28+
ignoreBlankLines :: ([Text] -> [Text]) -> Text -> Text
29+
ignoreBlankLines f text = Text.unlines $ leading ++ f within ++ trailing
30+
where
31+
rawLines = Text.lines text
32+
(leading, mid) = span blankLine rawLines
33+
(within, trailing) = spanEnd blankLine mid
34+
35+
cmtOrUncmt :: Cmt -> [Text] -> [Text]
36+
cmtOrUncmt cmt lines
37+
| shouldCmt cmt lines = cmtLines cmt lines
38+
| otherwise = uncmtLines cmt lines
39+
40+
shouldCmt :: Cmt -> [Text] -> Bool
41+
shouldCmt cmt = not . all (\line -> isCmted cmt line || blankLine line)
42+
43+
isCmted :: Cmt -> Text -> Bool
44+
isCmted cmt line = cmt `Text.isPrefixOf` Text.dropWhile Char.isSpace line
45+
46+
cmtLines :: Cmt -> [Text] -> [Text]
47+
cmtLines cmt lines = map (lineCmt cmt (indentOf lines)) lines
48+
49+
indentOf :: [Text] -> Text
50+
indentOf = maybe "" id . minimumOn Text.length
51+
. map (Text.takeWhile Char.isSpace) . filter (not . blankLine)
52+
53+
lineCmt :: Cmt -> Text -> Text -> Text
54+
lineCmt cmt indent line
55+
| Text.null post = indent <> cmt
56+
| otherwise = indent <> cmt <> " " <> post
57+
where
58+
-- I don't use pre because the line may be blank.
59+
(_, post) = Text.splitAt (Text.length indent) line
60+
61+
uncmtLines :: Cmt -> [Text] -> [Text]
62+
uncmtLines cmt = map (uncmtLine cmt)
63+
64+
uncmtLine :: Cmt -> Text -> Text
65+
uncmtLine cmt line = let s = pre <> post in if blankLine s then "" else s
66+
where
67+
(pre, withCmt) = Text.breakOn cmt line
68+
post = dropSpace (Text.drop (Text.length cmt) withCmt)
69+
dropSpace t = if " " `Text.isPrefixOf` t then Text.drop 1 t else t
70+
71+
blankLine :: Text -> Bool
72+
blankLine = Text.all Char.isSpace
73+
74+
-- * util
75+
76+
spanEnd :: (a -> Bool) -> [a] -> ([a], [a])
77+
spanEnd f xs = (reverse post, reverse pre)
78+
where (pre, post) = span f (reverse xs)
79+
80+
minimumOn :: (Ord k) => (a -> k) -> [a] -> Maybe a
81+
minimumOn _ [] = Nothing
82+
minimumOn key xs = Just (List.foldl1' f xs)
83+
where f low x = if key x < key low then x else low
84+
85+
86+
-- * tests
87+
88+
{-
89+
test_cmtOrUncmt = do
90+
print $ ignoreBlankLines (const ["yohoho"]) " \n\n hi\n \n \n\n"
91+
92+
t0 = lineCmt "--" " " " hello"
93+
t1 = lineCmt "--" " " " "
94+
t2 = indentOf [" ho", " hi"]
95+
96+
tlines :: [Text]
97+
tlines = [" ho", "", " hi"]
98+
99+
tcmt :: Text
100+
tcmt = "--"
101+
102+
t3 = cmtOrUncmt "--" tlines
103+
t4 = cmtOrUncmt "--" [" --hi", "-- there"]
104+
-}

0 commit comments

Comments
 (0)