initial import (v0.1)
This commit is contained in:
commit
35f60507c6
241
GHCMod.hs
Normal file
241
GHCMod.hs
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
module Main where
|
||||||
|
|
||||||
|
import Control.Exception hiding (try)
|
||||||
|
import Data.Char
|
||||||
|
import Data.List
|
||||||
|
import Language.Haskell.Exts.Extension
|
||||||
|
import Language.Haskell.Exts.Parser hiding (parse)
|
||||||
|
import Language.Haskell.Exts.Syntax
|
||||||
|
import Prelude hiding (catch)
|
||||||
|
import System.Console.GetOpt
|
||||||
|
import System.Environment
|
||||||
|
import System.IO
|
||||||
|
import System.Process
|
||||||
|
import Text.ParserCombinators.Parsec
|
||||||
|
|
||||||
|
import Debug.Trace
|
||||||
|
infixr 0 .$.
|
||||||
|
(.$.) :: Show a => (a -> b) -> a -> b
|
||||||
|
f .$. x = trace (show x) f x
|
||||||
|
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
usage :: String
|
||||||
|
usage = "ghc-mod putStrLn version 0.1\n"
|
||||||
|
++ "Usage:\n"
|
||||||
|
++ "\t ghc-mod list\n"
|
||||||
|
++ "\t ghc-mod browse <module>\n"
|
||||||
|
++ "\t ghc-mod help\n"
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
data Options = Options { optToLisp :: Bool
|
||||||
|
} deriving Show
|
||||||
|
|
||||||
|
defaultOptions :: Options
|
||||||
|
defaultOptions = Options { optToLisp = False
|
||||||
|
}
|
||||||
|
|
||||||
|
argspec :: [OptDescr (Options -> Options)]
|
||||||
|
argspec = [ Option ['l'] ["tolisp"]
|
||||||
|
(NoArg (\opts -> opts { optToLisp = True }))
|
||||||
|
"print as a list of Lisp"
|
||||||
|
]
|
||||||
|
|
||||||
|
parseArgs :: [OptDescr (Options -> Options)] -> [String] -> (Options, [String])
|
||||||
|
parseArgs spec argv
|
||||||
|
= case getOpt Permute spec argv of
|
||||||
|
(o,n,[] ) -> (foldl (flip id) defaultOptions o, n)
|
||||||
|
(_,_,errs) -> error (concat errs ++ usageInfo usage argspec)
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = flip catch handler $ do
|
||||||
|
args <- getArgs
|
||||||
|
let (opt,cmdArg) = parseArgs argspec args
|
||||||
|
transform = if optToLisp opt then toLisp else toPlain
|
||||||
|
ll <- case cmdArg !! 0 of
|
||||||
|
cmd | cmd == "browse" -> browseModule $ cmdArg !! 1
|
||||||
|
| cmd == "list" -> listModules
|
||||||
|
_ -> error usage
|
||||||
|
putStr $ transform $ nub $ sort $ ll
|
||||||
|
where
|
||||||
|
handler :: ErrorCall -> IO ()
|
||||||
|
-- handler _ = print usage
|
||||||
|
handler e = print e
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
browseModule :: String -> IO [String]
|
||||||
|
browseModule mname = do
|
||||||
|
xs <- getSyntax mname
|
||||||
|
let ys = preprocess xs
|
||||||
|
return $ parseSyntax ys
|
||||||
|
|
||||||
|
getSyntax :: String -> IO String
|
||||||
|
getSyntax mname = do
|
||||||
|
(inp,out,_,_) <- runInteractiveProcess "ghci" [] Nothing Nothing
|
||||||
|
mapM_ setFD [inp,out]
|
||||||
|
hPutStrLn inp ":set prompt \"\""
|
||||||
|
hPutStrLn inp "1"
|
||||||
|
hPutStrLn inp $ ":browse " ++ mname
|
||||||
|
hPutStrLn inp ":set prompt \"Prelude>\""
|
||||||
|
hPutStrLn inp ":quit"
|
||||||
|
cs <- hGetContents out
|
||||||
|
return $ unlines $ dropTailer $ dropHeader $ lines $ cs
|
||||||
|
where
|
||||||
|
isNotPrefixOf x y = not (x `isPrefixOf` y)
|
||||||
|
dropHeader xs = tail $ dropWhile (isNotPrefixOf "Prelude>") xs
|
||||||
|
dropTailer = takeWhile (isNotPrefixOf "Prelude>")
|
||||||
|
setFD h = do
|
||||||
|
hSetBinaryMode h False
|
||||||
|
hSetBuffering h LineBuffering
|
||||||
|
|
||||||
|
parseSyntax :: String -> [String]
|
||||||
|
parseSyntax xs = do
|
||||||
|
let mode = defaultParseMode { extensions = NewQualifiedOperators : ExplicitForall : glasgowExts }
|
||||||
|
res = parseModuleWithMode mode xs
|
||||||
|
case res of
|
||||||
|
ParseOk x -> identifiers x
|
||||||
|
-- e -> error $ show e
|
||||||
|
_ -> []
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
listModules :: IO [String]
|
||||||
|
listModules = do
|
||||||
|
cs <- getDump
|
||||||
|
return $ exposedModules cs
|
||||||
|
|
||||||
|
getDump :: IO String
|
||||||
|
getDump = do
|
||||||
|
(_,hout,_,_) <- runInteractiveProcess "ghc-pkg" ["dump"] Nothing Nothing
|
||||||
|
hGetContents hout
|
||||||
|
|
||||||
|
exposedModules :: String -> [String]
|
||||||
|
exposedModules cs = let ls = unfoldLines cs
|
||||||
|
ns = values "name: " ls
|
||||||
|
ms = values "exposed-modules: " ls
|
||||||
|
zs = zip ns ms
|
||||||
|
xs = filter (\(nm,_) -> nm `notElem` ["ghc", "ghc-prim", "rts", "integer"]) zs
|
||||||
|
ss = map snd xs
|
||||||
|
in filter (\x -> not ("GHC" `isPrefixOf` x)) $ concatMap words ss
|
||||||
|
|
||||||
|
values :: String -> [String] -> [String]
|
||||||
|
values tag ls = let len = length tag
|
||||||
|
fs = filter (tag `isPrefixOf`) ls
|
||||||
|
in map (drop len) fs
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
unfoldLines :: String -> [String]
|
||||||
|
unfoldLines xs = self xs
|
||||||
|
where
|
||||||
|
splitNL = break (== '\n')
|
||||||
|
self "" = []
|
||||||
|
self s = let (l, s') = splitNL s
|
||||||
|
in case s' of
|
||||||
|
[] -> [l]
|
||||||
|
(_:' ':s'') -> cont s'' l
|
||||||
|
(_:s'') -> l : self s''
|
||||||
|
cont s a = let (l, s') = splitNL $ dropWhile (== ' ') s
|
||||||
|
a' = a ++ " " ++ l
|
||||||
|
in case s' of
|
||||||
|
[] -> [a']
|
||||||
|
(_:' ':s'') -> cont s'' a'
|
||||||
|
(_:s'') -> a' : self s''
|
||||||
|
|
||||||
|
toLisp :: [String] -> String
|
||||||
|
toLisp ms = "(" ++ unwords quoted ++ ")\n"
|
||||||
|
where
|
||||||
|
quote x = "\"" ++ x ++ "\""
|
||||||
|
quoted = map quote ms
|
||||||
|
|
||||||
|
toPlain :: [String] -> String
|
||||||
|
toPlain = unlines
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
preprocess :: String -> String
|
||||||
|
preprocess cs = case parse remove "remove" cs of
|
||||||
|
Right a -> a
|
||||||
|
Left e -> error $ show e
|
||||||
|
|
||||||
|
modName :: Parser String
|
||||||
|
modName = do c <- oneOf ['A'..'Z']
|
||||||
|
cs <- many1 $ oneOf $ ['A'..'Z'] ++ ['a'..'z'] ++ ['0'..'9'] ++ "_'#"
|
||||||
|
return $ c:cs
|
||||||
|
|
||||||
|
anyName :: Parser String
|
||||||
|
anyName = many1 $ oneOf $ ['A'..'Z'] ++ ['a'..'z'] ++ ['0'..'9'] ++ "_'#"
|
||||||
|
|
||||||
|
manyBefore :: Show tok => GenParser tok st a -> GenParser tok st [tok] -> GenParser tok st [a]
|
||||||
|
manyBefore p anchor = manyTill p (eof <|> try anc)
|
||||||
|
where
|
||||||
|
anc = do pos <- getPosition
|
||||||
|
s <- anchor
|
||||||
|
ss <- getInput
|
||||||
|
setInput $ s ++ ss
|
||||||
|
setPosition pos
|
||||||
|
return ()
|
||||||
|
|
||||||
|
keyword :: Parser String
|
||||||
|
keyword = do ms <- modName
|
||||||
|
char '.'
|
||||||
|
return $ ms ++ ['.']
|
||||||
|
|
||||||
|
ghcName :: Parser String
|
||||||
|
ghcName = do keyword
|
||||||
|
try sep <|> end
|
||||||
|
where
|
||||||
|
sep = do
|
||||||
|
ws <- sepBy1 anyName (char '.')
|
||||||
|
return $ last ws
|
||||||
|
end = do
|
||||||
|
endBy1 anyName (char '.')
|
||||||
|
return ""
|
||||||
|
|
||||||
|
nonGhcName :: Parser String
|
||||||
|
nonGhcName = do c <- anyChar -- making this func non-empty
|
||||||
|
cs <- manyBefore anyChar keyword
|
||||||
|
return $ c:cs
|
||||||
|
|
||||||
|
remove :: Parser String
|
||||||
|
remove = do l1 <- try ghcName <|> return ""
|
||||||
|
l2 <- nonGhcName
|
||||||
|
ll <- many (do x <- ghcName
|
||||||
|
y <- nonGhcName
|
||||||
|
return $ x ++ y)
|
||||||
|
return $ concat $ l1 : l2 : ll
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
identifiers :: Module -> [String]
|
||||||
|
identifiers (Module _ _ _ _ _ _ x) = filter hid $ concatMap decl x
|
||||||
|
where
|
||||||
|
hid = all (\c -> isAlphaNum c || elem c "_'")
|
||||||
|
|
||||||
|
decl :: Decl -> [String]
|
||||||
|
decl (TypeSig _ [x] _) = [name x]
|
||||||
|
decl (DataDecl _ _ _ x _ y _) = name x : (map qualConDecl y)
|
||||||
|
decl (ClassDecl _ _ x _ _ y) = name x : (map classDecl y)
|
||||||
|
decl (TypeDecl _ x _ _) = [name x]
|
||||||
|
decl x = [show x]
|
||||||
|
|
||||||
|
qualConDecl :: QualConDecl -> String
|
||||||
|
qualConDecl (QualConDecl _ _ _ x) = conDecl x
|
||||||
|
|
||||||
|
conDecl :: ConDecl -> String
|
||||||
|
conDecl (ConDecl (Ident x) _) = x
|
||||||
|
conDecl (InfixConDecl _ (Ident x) _) = x
|
||||||
|
conDecl x = show x
|
||||||
|
|
||||||
|
classDecl :: ClassDecl -> String
|
||||||
|
classDecl (ClsDecl x) = concat $ decl x -- xxx
|
||||||
|
classDecl x = show x
|
||||||
|
|
||||||
|
name :: Name -> String
|
||||||
|
name (Symbol x) = x
|
||||||
|
name (Ident x) = x
|
16
elisp/Makefile
Normal file
16
elisp/Makefile
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
SRCS = ghc.el ghc-func.el ghc-doc.el ghc-comp.el
|
||||||
|
|
||||||
|
TEMPFILE = temp.el
|
||||||
|
|
||||||
|
all: $(TEMPFILE) ghc.el
|
||||||
|
emacs -batch -q -no-site-file -l ./$(TEMPFILE) -f ghc-compile
|
||||||
|
|
||||||
|
$(TEMPFILE):
|
||||||
|
@echo '(setq load-path (cons "." load-path))' >> $(TEMPFILE)
|
||||||
|
@echo '(defun ghc-compile () (mapcar (lambda (x) (byte-compile-file x)) (list ' >> $(TEMPFILE)
|
||||||
|
@echo $(SRCS)| sed -e 's/\(ghc[^ ]*\.el\)/"\1"/g' >> $(TEMPFILE)
|
||||||
|
@echo ')))' >> $(TEMPFILE)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.elc $(TEMPFILE)
|
||||||
|
|
183
elisp/ghc-comp.el
Normal file
183
elisp/ghc-comp.el
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;
|
||||||
|
;;; ghc-comp.el
|
||||||
|
;;;
|
||||||
|
|
||||||
|
;; Author: Kazu Yamamoto <Kazu@Mew.org>
|
||||||
|
;; Created: Sep 25, 2009
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(require 'ghc-func)
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;
|
||||||
|
;;; Customize Variables
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(defvar ghc-module-command "ghc-mod")
|
||||||
|
|
||||||
|
(defvar ghc-idle-timer-interval 30)
|
||||||
|
|
||||||
|
;; must be sorted
|
||||||
|
(defvar ghc-reserved-keyword-for-bol '("class" "data" "default" "import" "infix" "infixl" "infixr" "instance" "main" "module" "newtype" "type"))
|
||||||
|
|
||||||
|
;; must be sorted
|
||||||
|
(defvar ghc-reserved-keyword '("case" "deriving" "do" "else" "if" "in" "let" "module" "of" "then" "where"))
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;
|
||||||
|
;;; Initializer
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(defvar ghc-module-names nil) ;; completion for "import"
|
||||||
|
(defvar ghc-merged-keyword nil) ;; completion for type/func/...
|
||||||
|
|
||||||
|
(defvar ghc-keyword-prefix "ghc-keyword-")
|
||||||
|
(defvar ghc-keyword-Prelude nil)
|
||||||
|
(defvar ghc-loaded-module nil)
|
||||||
|
|
||||||
|
(defun ghc-comp-init ()
|
||||||
|
(setq ghc-module-names (ghc-load-keyword "list"))
|
||||||
|
(setq ghc-keyword-Prelude (ghc-load-keyword "browse" "Prelude"))
|
||||||
|
(setq ghc-loaded-module '("Prelude"))
|
||||||
|
(ghc-merge-keywords)
|
||||||
|
(run-with-idle-timer ghc-idle-timer-interval 'repeat 'ghc-idle-timer))
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;
|
||||||
|
;;; Executing command
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(defun ghc-load-keyword (&rest args)
|
||||||
|
(when (ghc-which ghc-module-command)
|
||||||
|
(ghc-read-lisp
|
||||||
|
(lambda ()
|
||||||
|
(let ((msg (mapconcat 'identity (cons ghc-module-command args) " ")))
|
||||||
|
(message "Executing \"%s\"..." msg)
|
||||||
|
(apply 'call-process-shell-command
|
||||||
|
ghc-module-command nil t nil (cons "-l" args))
|
||||||
|
(message "Executing \"%s\"...done" msg))))))
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;
|
||||||
|
;;; Completion
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(defvar ghc-completion-buffer-name "*Completions*")
|
||||||
|
|
||||||
|
(defun ghc-complete ()
|
||||||
|
(interactive)
|
||||||
|
(if (ghc-should-scroll)
|
||||||
|
(ghc-scroll-completion-buffer)
|
||||||
|
(ghc-try-complete)))
|
||||||
|
|
||||||
|
(defun ghc-should-scroll ()
|
||||||
|
(let ((window (ghc-completion-window)))
|
||||||
|
(and (eq last-command this-command)
|
||||||
|
window (window-live-p window) (window-buffer window)
|
||||||
|
(buffer-name (window-buffer window)))))
|
||||||
|
|
||||||
|
(defun ghc-scroll-completion-buffer ()
|
||||||
|
(let ((window (ghc-completion-window)))
|
||||||
|
(with-current-buffer (window-buffer window)
|
||||||
|
(if (pos-visible-in-window-p (point-max) window)
|
||||||
|
(set-window-start window (point-min))
|
||||||
|
(save-selected-window
|
||||||
|
(select-window window)
|
||||||
|
(scroll-up))))))
|
||||||
|
|
||||||
|
(defun ghc-completion-window ()
|
||||||
|
(get-buffer-window ghc-completion-buffer-name 0))
|
||||||
|
|
||||||
|
(defun ghc-try-complete ()
|
||||||
|
(let* ((end (point))
|
||||||
|
(symbols (ghc-select-completion-symbol))
|
||||||
|
(beg (ghc-completion-start-point))
|
||||||
|
(pattern (buffer-substring-no-properties beg end))
|
||||||
|
(completion (try-completion pattern symbols)))
|
||||||
|
(cond
|
||||||
|
((eq completion t) ;; completed
|
||||||
|
) ;; do nothing
|
||||||
|
((null completion) ;; no completions
|
||||||
|
(ding))
|
||||||
|
((not (string= pattern completion)) ;; ???
|
||||||
|
(delete-region beg end)
|
||||||
|
(insert completion)
|
||||||
|
(delete-other-windows))
|
||||||
|
(t ;; multiple completions
|
||||||
|
(let* ((list0 (all-completions pattern symbols))
|
||||||
|
(list (sort list0 'string<)))
|
||||||
|
(if (> (length list) 1)
|
||||||
|
(with-output-to-temp-buffer ghc-completion-buffer-name
|
||||||
|
(display-completion-list list pattern))
|
||||||
|
(delete-other-windows)))))))
|
||||||
|
|
||||||
|
(defun ghc-select-completion-symbol ()
|
||||||
|
(cond
|
||||||
|
((or (minibufferp)
|
||||||
|
(save-excursion
|
||||||
|
(beginning-of-line)
|
||||||
|
(looking-at "import ")))
|
||||||
|
ghc-module-names)
|
||||||
|
((or (bolp)
|
||||||
|
(let ((end (point)))
|
||||||
|
(save-excursion
|
||||||
|
(beginning-of-line)
|
||||||
|
(not (search-forward " " end t)))))
|
||||||
|
ghc-reserved-keyword-for-bol)
|
||||||
|
(t ghc-merged-keyword)))
|
||||||
|
|
||||||
|
(defun ghc-completion-start-point ()
|
||||||
|
(save-excursion
|
||||||
|
(let ((beg (save-excursion (beginning-of-line) (point))))
|
||||||
|
(if (search-backward " " beg t)
|
||||||
|
(1+ (point))
|
||||||
|
beg))))
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;
|
||||||
|
;;; Background Idle Timer
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(defun ghc-idle-timer ()
|
||||||
|
(let ((mods (ghc-gather-import-modules))
|
||||||
|
keywords)
|
||||||
|
(dolist (mod mods)
|
||||||
|
(when (and (member mod ghc-module-names)
|
||||||
|
(not (member mod ghc-loaded-module)))
|
||||||
|
(setq keywords (ghc-load-keyword "browse" mod))
|
||||||
|
(when (or (consp keywords) (null keywords))
|
||||||
|
(set (intern (concat ghc-keyword-prefix mod)) keywords)
|
||||||
|
(setq ghc-loaded-module (cons mod ghc-loaded-module)))))
|
||||||
|
(ghc-merge-keywords)))
|
||||||
|
|
||||||
|
(defun ghc-gather-import-modules ()
|
||||||
|
(let ((bufs (mapcar 'buffer-name (buffer-list)))
|
||||||
|
ret)
|
||||||
|
(save-excursion
|
||||||
|
(dolist (buf bufs)
|
||||||
|
(when (string-match "\\.hs$" buf)
|
||||||
|
(set-buffer buf)
|
||||||
|
(setq ret (cons (ghc-gather-import-modules-buffer) ret)))))
|
||||||
|
(ghc-uniq-lol ret)))
|
||||||
|
|
||||||
|
(defun ghc-gather-import-modules-buffer ()
|
||||||
|
(let (ret)
|
||||||
|
(save-excursion
|
||||||
|
(goto-char (point-min))
|
||||||
|
(while (re-search-forward "^import *\\([^\n ]+\\)" nil t)
|
||||||
|
(setq ret (cons (match-string-no-properties 1) ret))
|
||||||
|
(forward-line)))
|
||||||
|
ret))
|
||||||
|
|
||||||
|
(defun ghc-merge-keywords ()
|
||||||
|
(let* ((modkeys (mapcar 'ghc-module-keyword ghc-loaded-module))
|
||||||
|
(keywords (cons ghc-reserved-keyword modkeys))
|
||||||
|
(uniq-sorted (sort (ghc-uniq-lol keywords) 'string<)))
|
||||||
|
(setq ghc-merged-keyword uniq-sorted)))
|
||||||
|
|
||||||
|
(defun ghc-module-keyword (mod)
|
||||||
|
(symbol-value (intern (concat ghc-keyword-prefix mod))))
|
||||||
|
|
||||||
|
(provide 'ghc-comp)
|
64
elisp/ghc-doc.el
Normal file
64
elisp/ghc-doc.el
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;
|
||||||
|
;;; ghc.el
|
||||||
|
;;;
|
||||||
|
|
||||||
|
;; Author: Kazu Yamamoto <Kazu@Mew.org>
|
||||||
|
;; Created: Sep 25, 2009
|
||||||
|
|
||||||
|
(require 'ghc-func)
|
||||||
|
(require 'ghc-comp)
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(defun ghc-browse-document ()
|
||||||
|
(interactive)
|
||||||
|
(let* ((mod0 (ghc-extract-module))
|
||||||
|
(mod (ghc-read-module-name mod0))
|
||||||
|
(pkg (ghc-resolve-package-name mod)))
|
||||||
|
(ghc-display-document pkg mod)))
|
||||||
|
|
||||||
|
(defun ghc-extract-module ()
|
||||||
|
(interactive)
|
||||||
|
(save-excursion
|
||||||
|
(beginning-of-line)
|
||||||
|
(when (looking-at "^import +\\([^ \n]+\\)")
|
||||||
|
(match-string-no-properties 1))))
|
||||||
|
|
||||||
|
(defun ghc-resolve-package-name (mod)
|
||||||
|
(with-temp-buffer
|
||||||
|
(call-process "ghc-pkg" nil t nil "find-module" "--simple-output" mod)
|
||||||
|
(goto-char (point-min))
|
||||||
|
(when (looking-at "^\\([^-]+\\)-")
|
||||||
|
(match-string-no-properties 1))))
|
||||||
|
|
||||||
|
(defun ghc-resolve-document-path (pkg)
|
||||||
|
(with-temp-buffer
|
||||||
|
(call-process "ghc-pkg" nil t nil "field" pkg "haddock-html")
|
||||||
|
(goto-char (point-min))
|
||||||
|
(when (looking-at "^haddock-html: \\([^ \n]+\\)$")
|
||||||
|
(match-string-no-properties 1))))
|
||||||
|
|
||||||
|
(defun ghc-display-document (pkg mod)
|
||||||
|
(when (and pkg mod)
|
||||||
|
(let* ((mod- (ghc-replace-character mod ?. ?-))
|
||||||
|
(path (ghc-resolve-document-path pkg))
|
||||||
|
(url (format "file://%s/%s.html" path mod-)))
|
||||||
|
(browse-url url))))
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
(defvar ghc-input-map nil)
|
||||||
|
|
||||||
|
(unless ghc-input-map
|
||||||
|
(setq ghc-input-map
|
||||||
|
(if (boundp 'minibuffer-local-map)
|
||||||
|
(copy-keymap minibuffer-local-map)
|
||||||
|
(make-sparse-keymap)))
|
||||||
|
(define-key ghc-input-map "\t" 'ghc-complete))
|
||||||
|
|
||||||
|
(defun ghc-read-module-name (def)
|
||||||
|
(read-from-minibuffer "Module name: " def ghc-input-map))
|
||||||
|
|
||||||
|
|
||||||
|
(provide 'ghc-doc)
|
41
elisp/ghc-func.el
Normal file
41
elisp/ghc-func.el
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;
|
||||||
|
;;; ghc-func.el
|
||||||
|
;;;
|
||||||
|
|
||||||
|
;; Author: Kazu Yamamoto <Kazu@Mew.org>
|
||||||
|
;; Created: Sep 25, 2009
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(defun ghc-replace-character (string from to)
|
||||||
|
"Replace characters equal to FROM to TO in STRING."
|
||||||
|
(dotimes (cnt (length string) string)
|
||||||
|
(if (char-equal (aref string cnt) from)
|
||||||
|
(aset string cnt to))))
|
||||||
|
|
||||||
|
(defun ghc-which (cmd)
|
||||||
|
(catch 'loop
|
||||||
|
(dolist (dir exec-path)
|
||||||
|
(let ((path (expand-file-name cmd dir)))
|
||||||
|
(if (file-exists-p path)
|
||||||
|
(throw 'loop path))))))
|
||||||
|
|
||||||
|
(defun ghc-uniq-lol (lol)
|
||||||
|
(let ((hash (make-hash-table :test 'equal))
|
||||||
|
ret)
|
||||||
|
(dolist (lst lol)
|
||||||
|
(dolist (key lst)
|
||||||
|
(puthash key key hash)))
|
||||||
|
(maphash (lambda (key val) (setq ret (cons key ret))) hash)
|
||||||
|
ret))
|
||||||
|
|
||||||
|
(defun ghc-read-lisp (func)
|
||||||
|
(with-temp-buffer
|
||||||
|
(funcall func)
|
||||||
|
(goto-char (point-min))
|
||||||
|
(condition-case nil
|
||||||
|
(read (current-buffer))
|
||||||
|
(error ()))))
|
||||||
|
|
||||||
|
(provide 'ghc-func)
|
46
elisp/ghc.el
Normal file
46
elisp/ghc.el
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;
|
||||||
|
;;; ghc.el
|
||||||
|
;;;
|
||||||
|
|
||||||
|
;; Author: Kazu Yamamoto <Kazu@Mew.org>
|
||||||
|
;; Created: Sep 25, 2009
|
||||||
|
;; Revised:
|
||||||
|
|
||||||
|
;; Put the following code to your "~/.emacs".
|
||||||
|
;;
|
||||||
|
;; (autoload 'ghc-init "ghc" nil t)
|
||||||
|
;; (add-hook 'haskell-mode-hook (lambda () (ghc-init)))
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(defvar ghc-version "0.1")
|
||||||
|
|
||||||
|
;; (require 'haskell-mode)
|
||||||
|
(require 'ghc-comp)
|
||||||
|
(require 'ghc-doc)
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;
|
||||||
|
;;; Customize Variables
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(defvar ghc-completion-key "\e\t")
|
||||||
|
(defvar ghc-document-key "\e\C-d")
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;
|
||||||
|
;;; Initializer
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(defvar ghc-initialized nil)
|
||||||
|
|
||||||
|
(defun ghc-init ()
|
||||||
|
(unless ghc-initialized
|
||||||
|
(define-key haskell-mode-map ghc-completion-key 'ghc-complete)
|
||||||
|
(define-key haskell-mode-map ghc-document-key 'ghc-browse-document)
|
||||||
|
(ghc-comp-init)
|
||||||
|
(setq ghc-initialized t)))
|
||||||
|
|
||||||
|
|
||||||
|
|
25
ghc-mod.cabal
Normal file
25
ghc-mod.cabal
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
-- -*- mode: Text; indent-tabs-mode: nil; -*-
|
||||||
|
Name: ghc-mod
|
||||||
|
Version: 0.1
|
||||||
|
Author: Kazu Yamamoto <kazu@Mew.org>
|
||||||
|
Maintainer: Kazu Yamamoto <kazu@Mew.org>
|
||||||
|
License: BSD3
|
||||||
|
Homepage: http://www.mew.org/~kazu/
|
||||||
|
Synopsis: Extracting names from modules
|
||||||
|
Description: "ghc-mod" lists up all installed modules
|
||||||
|
or extracts names of functions, classes,
|
||||||
|
and data declarations. "ghc-mod" is a
|
||||||
|
backend for completion on Emacs.
|
||||||
|
Category: Development
|
||||||
|
Cabal-Version: >= 1.2
|
||||||
|
Build-Type: Simple
|
||||||
|
Data-Dir: elisp
|
||||||
|
Data-Files: Makefile ghc.el ghc-func.el ghc-doc.el ghc-comp.el
|
||||||
|
Executable ghc-mod
|
||||||
|
Main-Is: GHCMod.hs
|
||||||
|
GHC-Options: -Wall
|
||||||
|
Build-Depends: base >= 4.0,
|
||||||
|
parsec >= 2.0.0.0,
|
||||||
|
process >= 1.0,
|
||||||
|
haskell-src-exts >= 1.0
|
||||||
|
|
Loading…
Reference in New Issue
Block a user