Git Product home page Git Product logo

intellij-haskforce's Introduction

HaskForce

Build Status Join the chat at https://gitter.im/carymrobbins/intellij-haskforce

The IntelliJ plugin for Haskell.

Want to get started right away? Check out the Quick Start Guide!

Getting involved

Want to contribute code? See the CONTRIBUTING doc for more info.

Follow @HaskForce on Twitter to stay up to date on new releases and work in progress.

Start a discussion on our gitter channel.

Do you IRC? Join #haskforce on freenode!

Building

Clone the repo -

% git clone https://github.com/carymrobbins/intellij-haskforce
% cd intellij-haskforce

Build with Gradle -

% ./gradlew assemble

You can then find your plugin zip archive in build/distributions -

% ls build/distributions

Developing

When hacking on HaskForce, you may need the following plugins -

  • Scala
  • PsiViewer - Useful for viewing parse trees
  • JFlex Support 1.5.1 - Generate lexers
  • Grammar Kit v2017.1.7 - Generate parsers

To import this project in IntelliJ, use File > Open, navigate to the project directory, then click OK.

A Gradle configuration prompt will appear. Be sure to uncheck Create a separate module per source set. Below is a recommended setup -

Running the plugin

You can use the runIde Gradle task from the command line or directly from IntelliJ -

Debugging the plugin

You can run the plugin as described above via IntelliJ to enable setting breakpoints and stepping through code.

If you wish to debug the external builder (e.g. the jps-plugin sub-project), you'll need to use the remote debugger. See the IntelliJ SDK DevGuide for more info.

Testing the plugin

You can run all tests using the standard Gradle task -

./gradlew test

intellij-haskforce's People

Contributors

adinapoli avatar bmjames avatar carymrobbins avatar charleso avatar chris-martin avatar dplusic avatar i-walker avatar jmmk avatar kasperjanssens avatar leanderk avatar niknetniko avatar pjonsson avatar robeverest avatar rodlogic avatar sheliaklyr avatar tobiasgwaaler avatar tolysz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

intellij-haskforce's Issues

Syntax highlighting breaks for multiline strings

It seems that multiline strings are generating the correct Psi tree but will temporarily display incorrect syntax highlighting if the backslashes (after the first line of the literal) are removed and replaced.

The PsiViewer shows the correct tree being produced, so I'm not sure how to create a test for this one yet.

s = "\
    \Remove any backslash (except the first one) and put it back.\
    \The syntax highlighting will break!\
    \To fix, modify the first line of this string literal.\
\"

On a semi-related note, it seems that spaces between a backslash and newline are considered a syntax error, even though GHC will compile it just fine. See issue #11.

Hlint detection is too automatic

Having Hlint in the path makes new projects use it without the user taking any action. If the project happens to be hlint-unfriendly that means a lot of bright-orange background in the editor.

On one hand this is a feature, but it also means that users who did not want Hlint for the project get it whether they asked for it or not. We do the same thing for stylish-haskell, but the difference is that the user takes action to reformat the code, it's not an automatic annotator running in the background.

Create a quick start guide

This can be a simple page added to the wiki and referenced in the readme. It should contain basic instructions to get a user up and running with the plugin, including configuration of external tools like hlint, stylish-haskell, etc.

Make Haskell Tools global

Anytime you create a new project you have to set the paths to the Haskell tools again. This is pretty annoying. Of all of the tools we use right now, I don't think any of them should be project-specific.

Reference resolve does not capture scope

Let's say we have two modules -

module Foo where
spam = putStrLn "foo"
-------
module Bar where
spam = putStrLn "bar"
-------
module Quux where
import Foo
main = spam

Jumping to the declaration of spam in Quux will give us two options, the one from Foo and the one from Bar. Ideally, it should already know it's the one from Foo. Not sure the best way to go about this yet, except possibly through ghc-mod -

$ ghc-mod info Quux.hs - spam
spam :: IO ()   -- Defined at /Users/crobbins/code/foo/Foo.hs:2:1

Or maybe, better yet, through an interactive ghc-modi session -

$ ghc-modi
info Quux.hs spam
spam :: IO ()   -- Defined at /Users/crobbins/code/foo/Foo.hs:2:1

Highlights of multiline HLint annotations

HLint annotations do not always cover the entire problem they highlight. This example (InternalLexer.hs in haskell-src-exts) gets highlighted from the beginning of "data" to the "| CFILE" line that is commented out, but most of the problems (camelCase) are the constructors called KW_ which are below the CFILE comment.

data Token
        = VarId String
        | QVarId (String,String)
        | IDupVarId (String)        -- duplicable implicit parameter
        | ILinVarId (String)        -- linear implicit parameter
        | ConId String
        | QConId (String,String)
        | DVarId [String]       -- to enable varid's with '-' in them
        | VarSym String
        | ConSym String
        | QVarSym (String,String)
        | QConSym (String,String)
        | IntTok (Integer, String)
        | FloatTok (Rational, String)
        | Character (Char, String)
        | StringTok (String, String)
        | IntTokHash (Integer, String)        -- 1#
        | WordTokHash (Integer, String)       -- 1##
        | FloatTokHash (Rational, String)     -- 1.0#
        | DoubleTokHash (Rational, String)    -- 1.0##
        | CharacterHash (Char, String)        -- c#
        | StringHash (String, String)         -- "Hello world!"#

-- Symbols

        | LeftParen
        | RightParen
        | LeftHashParen
        | RightHashParen
        | SemiColon
        | LeftCurly
        | RightCurly
        | VRightCurly           -- a virtual close brace
        | LeftSquare
        | RightSquare
        | ParArrayLeftSquare -- [:
        | ParArrayRightSquare -- :]
        | Comma
        | Underscore
        | BackQuote

-- Reserved operators

        | Dot           -- reserved for use with 'forall x . x'
        | DotDot
        | Colon
        | DoubleColon
        | Equals
        | Backslash
        | Bar
        | LeftArrow
        | RightArrow
        | At
        | Tilde
        | DoubleArrow
        | Minus
        | Exclamation
        | Star
        | LeftArrowTail         -- >-
        | RightArrowTail        -- -<
        | LeftDblArrowTail      -- >>-
        | RightDblArrowTail     -- -<<

-- Template Haskell
        | THExpQuote            -- [| or [e|
        | THPatQuote            -- [p|
        | THDecQuote            -- [d|
        | THTypQuote            -- [t|
        | THCloseQuote          -- |]
        | THIdEscape (String)   -- dollar x
        | THParenEscape         -- dollar (
        | THVarQuote            -- 'x (but without the x)
        | THTyQuote             -- ''T (but without the T)
        | THQuasiQuote (String,String)  -- [$...|...]

-- HaRP
        | RPGuardOpen       -- (|
        | RPGuardClose      -- |)
        | RPCAt             -- @:

-- Hsx
        | XCodeTagOpen      -- <%
        | XCodeTagClose     -- %>
        | XStdTagOpen       -- <
        | XStdTagClose      -- >
        | XCloseTagOpen     -- </
        | XEmptyTagClose    -- />
        | XChildTagOpen     -- <%> (note that close doesn't exist, it's XCloseTagOpen followed by XCodeTagClose)
        | XPCDATA String
        | XRPatOpen             -- <[
        | XRPatClose            -- ]>

-- Pragmas

        | PragmaEnd                     -- #-}
        | RULES
        | INLINE Bool
        | INLINE_CONLIKE
        | SPECIALISE
        | SPECIALISE_INLINE Bool
        | SOURCE
        | DEPRECATED
        | WARNING
        | SCC
        | GENERATED
        | CORE
        | UNPACK
        | OPTIONS (Maybe String,String)
--        | CFILES  String
--        | INCLUDE String
        | LANGUAGE
        | ANN
        | MINIMAL
        | NO_OVERLAP
        | OVERLAP
        | INCOHERENT

-- Reserved Ids

        | KW_As
        | KW_By         -- transform list comprehensions
        | KW_Case
        | KW_Class
        | KW_Data
        | KW_Default
        | KW_Deriving
        | KW_Do
        | KW_MDo
        | KW_Else
        | KW_Family     -- indexed type families
        | KW_Forall     -- universal/existential types
        | KW_Group      -- transform list comprehensions
        | KW_Hiding
        | KW_If
        | KW_Import
        | KW_In
        | KW_Infix
        | KW_InfixL
        | KW_InfixR
        | KW_Instance
        | KW_Let
        | KW_Module
        | KW_NewType
        | KW_Of
        | KW_Proc       -- arrows
        | KW_Rec        -- arrows
        | KW_Then
        | KW_Type
        | KW_Using      -- transform list comprehensions
        | KW_Where
        | KW_Qualified

                -- FFI
        | KW_Foreign
        | KW_Export
        | KW_Safe
        | KW_Unsafe
        | KW_Threadsafe
        | KW_Interruptible
        | KW_StdCall
        | KW_CCall
        | KW_CPlusPlus
        | KW_DotNet
        | KW_Jvm
        | KW_Js
        | KW_CApi

        | EOF
        deriving (Eq,Show)

Parser error with indented else in do block

The following snippet causes a parse error -

foo = do
    if True then
        let msg = "yep"
        in putStrLn msg
    else  -- <exp>, <pat>, HaskellTokenType.let or HaskellTokenType.rec expected, got 'else'
        putStrLn "nope"

I think this has to do with the parser thinking that the dedent for else is closing the do block. For instance, the following snippet parses fine -

foo = do
    if True then
        let msg = "yep"
        in putStrLn msg else putStrLn "nope"

Fix brace-matching fallout

The comment refactoring broke the TypedHandler matching. We're now getting a different token and the BraceMatcher gets lost. Will fix tomorrow.

Integrate ghc-mod

This issue is really a big parent ticket that has a LOT of prerequisites. However, I think this is a very practical goal for the project.

The awesome ghc-mod and ghc-modi tools provide a command line interface that should be usable by HaskForce.

http://www.mew.org/~kazu/proj/ghc-mod/en/

They can be installed with cabal install ghc-mod. We can have the IDE offer to do this for us via the to-be-implemented External Tools interface (cabal should be available there as well). Here's the intellij-erlang implementation:

https://github.com/ignatov/intellij-erlang/blob/master/src/org/intellij/erlang/settings/ErlangExternalToolsConfigurable.java

While it's a lot of work, tapping into ghc-mod should actually end up being a far simpler solution than implementing everything in IntelliJ. It doesn't take too long to install, so I think that having it as a requirement for reference, resolve, autocomplete, etc. features shouldn't be a big deal.

Robust configuration validation

We need to provide robust validation of the Haskell parts of IntelliJ configuration, and provide reasonable feedback when we can detect that something is wrong.

One idea is to provide early feedback through a checkmark when the versions of software is past a certain threshold in the configuration panel. We want Cabal 1.20 for -j building, ghc 7.8 for the same reason, and so on. We shouldn't stop working if those versions are not provided, but perhaps fall back into a less functional mode.

I think we will need some version of cabal available though because that's our only implemented builder. BuildWrapper also needs cabal to provide any help that is useful for us.

Parse error with quasi-quoting

The example below fails in the parseRoutes quasi-quoter. If we remove those lines, the parser also fails on the whamlet. Quasi-quotes should ideally parse anything until the next |].

{-# LANGUAGE QuasiQuotes           #-}
{-# LANGUAGE TemplateHaskell       #-}
{-# LANGUAGE TypeFamilies          #-}
import           Yesod

data HelloWorld = HelloWorld

mkYesod "HelloWorld" [parseRoutes|
/ HomeR GET
|]

instance Yesod HelloWorld

getHomeR :: Handler Html
getHomeR = defaultLayout [whamlet|Hello World!|]

main :: IO ()
main = warp 3000 HelloWorld

Travis build failure/error handling

@carymrobbins: Noticed you just did some tweaks to the travis build scripts. Can you take a look at this?

Getting a non-descriptive Err http://ppa.launchpad.net precise InRelease from the travis build and a bit after that it fails because it can't install the dependencies. Here's the log:

https://travis-ci.org/carymrobbins/intellij-haskforce/jobs/27606311

As a side note I'm guessing the build scripts should probably fail immediately if the installation of dependent packages fail. That's still a minor issue though since we can't recover from the situation.

Latency warnings from IntelliJ with new parser

IntelliJ puts warnings in the logs about long latencies with the new parser. No bad user experiences from it as far as I can tell, but investigate if we are violating some assumptions from IntelliJ.

Hlint --json error regions

The following code:

h_naive :: ([Length],[Word8]) -> Word16
h_naive = eval naive

Gets marked with camelCase suggestion from the beginning of the line until the a in eval. I don't get any warnings or similar in my log. Hlint flags the entire line:

[
  {
    "module": "Main",
    "decl": "h_naive",
    "severity": "Warning",
    "hint": "Use camelCase",
    "file": "CRC.hs",
    "startLine": 29,
    "startColumn": 1,
    "endLine": 29,
    "endColumn": 21,
    "from": "h_naive = ...",
    "to": "hNaive = ...",
    "note": [

    ]
  },
  {
    "module": "Main",
    "decl": "h_normal",
    "severity": "Warning",
    "hint": "Use camelCase",
    "file": "CRC.hs",
    "startLine": 33,
    "startColumn": 1,
    "endLine": 33,
    "endColumn": 23,
    "from": "h_normal = ...",
    "to": "hNormal = ...",
    "note": [

    ]
  }
]

Add Code Style for Haskell

Under Preferences > Code Style we should have a Haskell section. At the very least we should have a tab setting so the user can control the behavior of the tab key (4 spaces, 2 spaces, etc.).

Warning: cabal: Unrecognised flags: null

If you don't enter a flag in the Haskell Compiler > Cabal configure flags option, you get this error. Obviously, we should handle this case and not pass flags to cabal.

Collection ticket for syntax highlighting, underlining, etc

With the latest developments in #10 and #12 and my progress on parser implementation I'm now in a position to give a more informed opinion. This ticket is complementary to #7.

Our lexer is currently in reasonable shape for the files I've tried to open in IntelliJ, and that is what provides the syntax highlighting. It's not perfect, and part of the reason for that is that it's hard to see through Grammar-Kit which is both buggy in some places and lacking documentation in many others.

The parser seemed to shape up nicely with perfectly reasonable effort, making it seem feasible to implement something that is reasonable ghc-compatible in a few weeks of effort. I created a test case with two lines starting with "module .." and I got the nice red marks on the second line in my editor as expected. Once I got past the import statements things are looking pretty miserable though. Even to parse simple things we need an implementation of the layout algorithm (called L in chapter 10) to insert braces and semicolons in the right places. Inserting things into the lexer stream will certainly violate assumptions somewhere in IntelliJ. Implementing the layout algorithm is not a biggie, but if things keep piling up we're a long way from even having basic parser support for HaskForce.

Staying within IntelliJ has the advantage that we can leverage existing infrastructure, and that infrastructure has been performance tuned (I assume). The drawback is that we must implement everything from the compiler ourselves and on top of that adapt to the infrastructure which was not designed with Haskell in mind.

Leaving IntelliJ has the advantage that we can leverage a lot of Haskell tools, and GHC's parser and type checker are basically guaranteed to be compatible with the latest extensions. The drawback is that we might end up fighting the IntelliJ infrastructure while we are chasing a moving target (the GHC API is not stable). On top of that we introduce a source of potential bugs in the glue code, especially if we try to be clever and cache things. What is worst is perhaps the fundamental design differences: IntelliJ's idea of virtual file system is pretty deeply rooted, and that does not bode well for integrating Buildwrapper which uses a temporary directory in the file system.

I suggest the following course of action:

  1. Copy the generated _HaskellLexer.flex and wire that up with the syntax highlighting in IntelliJ. We get more control over the lexer, avoid bugs in Grammar-Kit, and get access to documentation since JFlex is a mature product.
  2. Glue to the GHC-API, either directly or through Buildwrapper, for building the Psi tree. This would mean we potentially get the entire sledgehammer diagnostics after the syntax highlighting, but it might effectively mean that it's in the third pass rather than the second. Buildwrapper uses JSON files in a temporary directory for communication, and has caching built in, so if that could fit in the IntelliJ model we would be pretty well off. If we want to glue immediately to GHC itself there seems to be ways to use the Haskell FFI and JNI (http://stackoverflow.com/questions/10370177/communication-between-java-and-haskell) using JavaCPP (https://github.com/bytedeco/javacpp).

Performing the first step does not force us commit to remove grammar-kit. If we decided to keep grammar-kit for the parser that would decouple the parser from the highlighting-lexer making the syntax highlighting unlikely to break unless modifying the "handwritten" lexer.

ghc-mod not picking up cabal settings

Not sure if this is our fault or a problem upstream, so reporting it here for starters.

https://github.com/Feldspar/feldspar-language needs -fcontext-stack=100 which is specified in the cabal file. ghc-mod does not seem to pick that up automatically, so Constructs.hs:217 gets a red mark on render relating to that context-stack overrun.

I'm using ghc-mod 5.0.1 compiled with ghc 7.8.3. I didn't need the context stack parameter with ghc 7.6.x.

Test Harp parsing

Add one or several haskell files in tests/gold/parser that test parsing of Harp extensions.

Example commit (text files are automatically generated): 43f9961

Intermittent `Unbalanced tree` error

When opening certain files (example file below) I get the following traceback. Currently investigating how to write a test case for this.

module Haggcat.Classes where

import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LBS

class Addable a where
    (<+>) :: a -> a -> a

instance Addable BS.ByteString where
    (<+>) = BS.append

instance Addable LBS.ByteString where
    (<+>) = LBS.append
Unbalanced tree. Most probably caused by unbalanced markers. Try calling setDebugMode(true) against PsiBuilder passed to identify exact location of the problem
java.lang.Throwable
    at com.intellij.openapi.diagnostic.Logger.error(Logger.java:113)
    at com.intellij.lang.impl.PsiBuilderImpl.prepareLightTree(PsiBuilderImpl.java:1133)
    at com.intellij.lang.impl.PsiBuilderImpl.buildTree(PsiBuilderImpl.java:1020)
    at com.intellij.lang.impl.PsiBuilderImpl.getTreeBuilt(PsiBuilderImpl.java:1005)
    at com.intellij.lang.impl.PsiBuilderAdapter.getTreeBuilt(PsiBuilderAdapter.java:121)
    at com.haskforce.parser.HaskellParser.parse(HaskellParser.java:258)
    at com.intellij.psi.tree.ILazyParseableElementType.doParseContents(ILazyParseableElementType.java:64)
    at com.intellij.psi.tree.IFileElementType.parseContents(IFileElementType.java:43)
    at com.intellij.psi.impl.source.tree.LazyParseableElement.ensureParsed(LazyParseableElement.java:166)
    at com.intellij.psi.impl.source.tree.LazyParseableElement.getFirstChildNode(LazyParseableElement.java:202)
    at com.intellij.psi.impl.source.tree.LazyParseableElement.getFirstChildNode(LazyParseableElement.java:34)
    at com.intellij.psi.impl.source.tree.SharedImplUtil.getFirstChild(SharedImplUtil.java:44)
    at com.intellij.psi.impl.source.PsiFileImpl.getFirstChild(PsiFileImpl.java:788)
    at com.intellij.psi.SingleRootFileViewProvider.findElementAt(SingleRootFileViewProvider.java:444)
    at com.intellij.psi.SingleRootFileViewProvider.findElementAt(SingleRootFileViewProvider.java:430)
    at com.intellij.psi.impl.source.PsiFileImpl.findElementAt(PsiFileImpl.java:609)
    at com.intellij.psi.util.PsiUtilCore.getElementAtOffset(PsiUtilCore.java:396)
    at com.intellij.psi.util.PsiUtilBase.getLanguageInEditor(PsiUtilBase.java:97)
    at com.intellij.psi.util.PsiUtilBase.getPsiFileInEditor(PsiUtilBase.java:123)
    at com.intellij.codeInsight.highlighting.BraceHighlightingHandler.lookForInjectedAndMatchBracesInOtherThread(BraceHighlightingHandler.java:117)
    at com.intellij.codeInsight.highlighting.BraceHighlighter.updateBraces(BraceHighlighter.java:125)
    at com.intellij.codeInsight.highlighting.BraceHighlighter$1.caretPositionChanged(BraceHighlighter.java:61)
    at sun.reflect.GeneratedMethodAccessor32.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.util.EventDispatcher.dispatch(EventDispatcher.java:90)
    at com.intellij.util.EventDispatcher.access$100(EventDispatcher.java:34)
    at com.intellij.util.EventDispatcher$1.invoke(EventDispatcher.java:67)
    at com.sun.proxy.$Proxy25.caretPositionChanged(Unknown Source)
    at sun.reflect.GeneratedMethodAccessor32.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.util.EventDispatcher.dispatch(EventDispatcher.java:90)
    at com.intellij.util.EventDispatcher.access$100(EventDispatcher.java:34)
    at com.intellij.util.EventDispatcher$1.invoke(EventDispatcher.java:67)
    at com.sun.proxy.$Proxy25.caretPositionChanged(Unknown Source)
    at com.intellij.openapi.editor.impl.CaretModelImpl.doMoveToLogicalPosition(CaretModelImpl.java:621)
    at com.intellij.openapi.editor.impl.CaretModelImpl.moveToLogicalPosition(CaretModelImpl.java:450)
    at com.intellij.openapi.editor.impl.CaretModelImpl.moveToLogicalPosition(CaretModelImpl.java:430)
    at com.intellij.openapi.fileEditor.impl.text.TextEditorProvider.setStateImpl(TextEditorProvider.java:214)
    at com.intellij.openapi.fileEditor.impl.text.PsiAwareTextEditorProvider.setStateImpl(PsiAwareTextEditorProvider.java:124)
    at com.intellij.openapi.fileEditor.impl.text.TextEditorImpl.setState(TextEditorImpl.java:100)
    at com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl.openFileImpl4(FileEditorManagerImpl.java:863)
    at com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl.openFileImpl3(FileEditorManagerImpl.java:740)
    at com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl$8.run(FileEditorManagerImpl.java:720)
    at com.intellij.openapi.command.impl.CommandProcessorImpl.executeCommand(CommandProcessorImpl.java:124)
    at com.intellij.openapi.command.impl.CommandProcessorImpl.executeCommand(CommandProcessorImpl.java:99)
    at com.intellij.openapi.command.impl.CommandProcessorImpl.executeCommand(CommandProcessorImpl.java:85)
    at com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl.openFileImpl2(FileEditorManagerImpl.java:717)
    at com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl.openFileWithProviders(FileEditorManagerImpl.java:654)
    at com.intellij.openapi.fileEditor.ex.FileEditorManagerEx.openFile(FileEditorManagerEx.java:139)
    at com.intellij.codeInsight.navigation.NavigationUtil.activatePsiElementIfOpen(NavigationUtil.java:167)
    at com.intellij.codeInsight.navigation.NavigationUtil.openFileWithPsiElement(NavigationUtil.java:144)
    at com.intellij.ide.projectView.impl.nodes.AbstractPsiBasedNode.navigate(AbstractPsiBasedNode.java:207)
    at com.intellij.ide.projectView.impl.nodes.AbstractPsiBasedNode.navigate(AbstractPsiBasedNode.java:217)
    at com.intellij.ide.projectView.impl.nodes.PsiFileNode.navigate(PsiFileNode.java:132)
    at com.intellij.util.OpenSourceUtil.navigate(OpenSourceUtil.java:53)
    at com.intellij.util.OpenSourceUtil.openSourcesFrom(OpenSourceUtil.java:31)
    at com.intellij.util.EditSourceOnDoubleClickHandler$TreeMouseListener.processDoubleClick(EditSourceOnDoubleClickHandler.java:130)
    at com.intellij.util.EditSourceOnDoubleClickHandler$TreeMouseListener.onDoubleClick(EditSourceOnDoubleClickHandler.java:122)
    at com.intellij.ui.DoubleClickListener.onClick(DoubleClickListener.java:28)
    at com.intellij.ui.ClickListener$1.mouseReleased(ClickListener.java:73)
    at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:290)
    at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:289)
    at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:289)
    at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:289)
    at java.awt.Component.processMouseEvent(Component.java:6505)
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3320)
    at com.intellij.ui.treeStructure.Tree.processMouseEvent(Tree.java:420)
    at com.intellij.ide.dnd.aware.DnDAwareTree.processMouseEvent(DnDAwareTree.java:52)
    at java.awt.Component.processEvent(Component.java:6270)
    at java.awt.Container.processEvent(Container.java:2229)
    at java.awt.Component.dispatchEventImpl(Component.java:4861)
    at java.awt.Container.dispatchEventImpl(Container.java:2287)
    at java.awt.Component.dispatchEvent(Component.java:4687)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4832)
    at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4492)
    at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4422)
    at java.awt.Container.dispatchEventImpl(Container.java:2273)
    at java.awt.Window.dispatchEventImpl(Window.java:2719)
    at java.awt.Component.dispatchEvent(Component.java:4687)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:735)
    at java.awt.EventQueue.access$200(EventQueue.java:103)
    at java.awt.EventQueue$3.run(EventQueue.java:694)
    at java.awt.EventQueue$3.run(EventQueue.java:692)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
    at java.awt.EventQueue$4.run(EventQueue.java:708)
    at java.awt.EventQueue$4.run(EventQueue.java:706)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:705)
    at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:697)
    at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:520)
    at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:335)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

Recursive annotator causes noticeable delay

The annotator in HaskellAnnotator is apparently the key to making changed multiline strings as seen in #10 work. Terrence Parr has some notes [1], roughly indicating that his annotator gets called for every (changed) leaf.

Our annotator is looping over the children of each node in a loop though. Removing that loop makes a noticeable difference on my computer when scrolling in a 1000 line Haskell file, and the test case for #10 still works without the loop.

Since I was a bit worried abou the performance I also checked the performance of the visitor pattern compared to instanceof. Visitor is a lot faster, so that should stay.

Do we have a test case or an example that shows the need for the loop in our annotator, or should I remove it for now?

[1] https://theantlrguy.atlassian.net/wiki/display/~admin/Intellij+plugin+development+notes#Intellijplugindevelopmentnotes-Annotators

Test Hsx parsing

Add one or several haskell files in tests/gold/parser that test parsing of Hsx extensions.

Example commit (text files are automatically generated): 43f9961

Missing cabal file should cause a build error

As it currently stands, if your project doesn't have a cabal file you don't get a build error. We should definitely prompt a build error when this occurs. Optionally, we could offer to run cabal init for the user.

Cabal file support

  • We need to be able to provide syntax highlighting for .cabal files.
  • From an API standpoint, we should provide helper methods to simplify the retrieval of details such as build types, extensions, etc.
  • It would probably also be nice to simulate cabal init with a GUI form.

Error Java JDK isn't specified for module ..

Sometimes the cabal build does not rebuild anything, and we get the above error. Here's a console printout:

mac213:haskell-src-exts pj$ cabal build -j5
Building haskell-src-exts-1.15.0.1...
Preprocessing library haskell-src-exts-1.15.0.1...
In-place registering haskell-src-exts-1.15.0.1...
Preprocessing test suite 'test' for haskell-src-exts-1.15.0.1...
mac213:haskell-src-exts pj$ 

I'm not too worried about the error message, but the fact that it is signaled as an error is troublesome. Our primary mechanism for detecting errors are the return values from cabal, so maybe something is up with them.

Any type annotation is used for reference resolving

Explicit type annotations used for expressions are interpreted as declarations. For example -

foo = do
    x <- getLine
    print (read x :: Int)

In this case, the x in x <- getLine will resolve to the x in print (read x :: Int) because of the type signature. Really, it should be the other way around. However, that requires a new reference resolve feature for local variables. The best fix (for now) is probably figuring out how to separate a declaration type annotation from a return type annotation.

GHC configured in multiple locations

@pjonsson - I just realized that we have that path to GHC set explicitly under the Compiler section as well as implicitly by the SDK. It probably doesn't make sense to have it in both places. I would suggest keeping the SDK one since I'm not sure that the Compiler one is actually being used anywhere. It would probably make sense to put a label showing the GHC version with (maybe) a hyperlink to the SDK settings.

Ghc-mod annotations disappeared after upgrading ghc

I upgraded my ghc and reconfigured/recompiled the project. I didn't upgrade ghc-mod and annotations stopped appearing. Here's a manual check:

$ ghc-mod check src/Feldspar/Core/Constructs/Array.hs
src/Feldspar/Core/Constructs/Array.hs:0:0:Error:<command line>: cannot satisfy -package-id utf8-string-0.3.8-d701116f7741e309cbab22d49d3efaaa
    (use -v for more information)

I can see how a lot of people would end up in a similar situation when a new platform is released, so we probably want some kind of error handling for this scenario.

Create Run Configurations

I've already added an (incomplete) implementation here: 1cda2ad

This page provides a good explanation of the various components needed to get this working: http://confluence.jetbrains.com/display/IDEADEV/Run+Configurations

For cabal projects we can tap into cabal run or cabal test and just handle piping the input/output properly, which probably won't be too hard. We'll probably want to discuss how to handle non-cabal projects, and if there are any odd cases to be aware of.

We should also keep in mind that we'll need to implement debug configurations as well (probably a separate ticket). At the very least, it would be nice to disable the debug icon in the interface since we won't have an implementation for it at first.

Parser hangs on open comment

Steps to reproduce:

-- 1. Start a module.
module Foo where

-- 2. Type an open comment.
module {-Foo where

Parser then hangs (seemingly) for eternity.

IndexOutOfBoundsException for syntax error in list

Given the following module -

module Foo where

xs = [ "foo"
     ,
     ]

Place the cursor after the comma and press the spacebar. A space will not be inserted and the following traceback is displayed -

chars sequence.length:2274, start:2274, end:0: chars sequence.length:2274, start:2274, end:0
java.lang.IndexOutOfBoundsException: chars sequence.length:2274, start:2274, end:0
    at com.intellij.util.text.CharSequenceSubSequence.<init>(CharSequenceSubSequence.java:32)
    at com.intellij.util.text.ImmutableText.subSequence(ImmutableText.java:383)
    at com.intellij.lang.impl.PsiBuilderImpl.getTokenText(PsiBuilderImpl.java:790)
    at com.intellij.lang.impl.PsiBuilderAdapter.getTokenText(PsiBuilderAdapter.java:96)
    at com.intellij.lang.parser.GeneratedParserUtilBase.reportError(GeneratedParserUtilBase.java:607)
    at com.intellij.lang.parser.GeneratedParserUtilBase.exit_section_(GeneratedParserUtilBase.java:479)
    at com.haskforce.parser.HaskellParser.parse(HaskellParser.java:230)
    at com.haskforce.psi.HaskellParserWrapper.parse(HaskellParserWrapper.java:55)
    at com.intellij.psi.tree.ILazyParseableElementType.doParseContents(ILazyParseableElementType.java:64)
    at com.intellij.psi.tree.IFileElementType.parseContents(IFileElementType.java:43)
    at com.intellij.psi.impl.source.tree.LazyParseableElement.ensureParsed(LazyParseableElement.java:172)
    at com.intellij.psi.impl.source.tree.LazyParseableElement.getFirstChildNode(LazyParseableElement.java:212)
    at com.intellij.psi.impl.source.tree.LazyParseableElement.getFirstChildNode(LazyParseableElement.java:36)
    at com.intellij.psi.impl.source.tree.SharedImplUtil.getFirstChild(SharedImplUtil.java:44)
    at com.intellij.psi.impl.source.PsiFileImpl.getFirstChild(PsiFileImpl.java:788)
    at com.intellij.psi.SingleRootFileViewProvider.findElementAt(SingleRootFileViewProvider.java:444)
    at com.intellij.psi.SingleRootFileViewProvider.findElementAt(SingleRootFileViewProvider.java:430)
    at com.intellij.psi.impl.source.PsiFileImpl.findElementAt(PsiFileImpl.java:609)
    at idea.plugin.psiviewer.view.PsiViewerPanel.selectElementAtCaret(PsiViewerPanel.java:326)
    at idea.plugin.psiviewer.view.PsiViewerPanel.selectElementAtCaret(PsiViewerPanel.java:312)
    at idea.plugin.psiviewer.controller.project.PsiViewerProjectComponent.handleCurrentState(PsiViewerProjectComponent.java:153)
    at idea.plugin.psiviewer.controller.project.PsiViewerProjectComponent.access$000(PsiViewerProjectComponent.java:50)
    at idea.plugin.psiviewer.controller.project.PsiViewerProjectComponent$1.propertyChange(PsiViewerProjectComponent.java:103)
    at java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:339)
    at java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:347)
    at java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:276)
    at java.awt.Component.firePropertyChange(Component.java:8287)
    at javax.swing.JComponent.addNotify(JComponent.java:4694)
    at java.awt.Container.addNotify(Container.java:2621)
    at javax.swing.JComponent.addNotify(JComponent.java:4693)
    at java.awt.Container.addNotify(Container.java:2621)
    at javax.swing.JComponent.addNotify(JComponent.java:4693)
    at java.awt.Container.addNotify(Container.java:2621)
    at javax.swing.JComponent.addNotify(JComponent.java:4693)
    at java.awt.Container.addNotify(Container.java:2621)
    at javax.swing.JComponent.addNotify(JComponent.java:4693)
    at java.awt.Container.addNotify(Container.java:2621)
    at javax.swing.JComponent.addNotify(JComponent.java:4693)
    at java.awt.Container.addNotify(Container.java:2621)
    at javax.swing.JComponent.addNotify(JComponent.java:4693)
    at java.awt.Container.addNotify(Container.java:2621)
    at javax.swing.JComponent.addNotify(JComponent.java:4693)
    at java.awt.Container.addImpl(Container.java:1067)
    at java.awt.Container.add(Container.java:363)
    at com.intellij.openapi.ui.ThreeComponentsSplitter.setLastComponent(ThreeComponentsSplitter.java:344)
    at com.intellij.openapi.wm.impl.ToolWindowsPane.setComponent(ToolWindowsPane.java:370)
    at com.intellij.openapi.wm.impl.ToolWindowsPane.access$500(ToolWindowsPane.java:51)
    at com.intellij.openapi.wm.impl.ToolWindowsPane$AddDockedComponentCmd.run(ToolWindowsPane.java:721)
    at com.intellij.openapi.application.impl.LaterInvocator$FlushQueue.run(LaterInvocator.java:319)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:715)
    at java.awt.EventQueue.access$400(EventQueue.java:82)
    at java.awt.EventQueue$2.run(EventQueue.java:676)
    at java.awt.EventQueue$2.run(EventQueue.java:674)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:86)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:685)
    at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:697)
    at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:524)
    at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:335)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

HLint needs language extensions from the cabal file

If a Haskell source file implicitly requires a language extension from the cabal file (e.g. QuasiQuotes) we need to pass this to the hlint executable using the -X switch. Otherwise, hlint will report parse errors.

HLint annotations stopped appearing

HLint annotations stopped appearing. I don't think I did anything special. The configuration values are correct, and it can detect the version. Here's something from my log that might be related:

2014-07-11 01:00:55,430 [5797185]   INFO - agnostic.FrequentEventDetector - Too many events posted
java.lang.Throwable
    at com.intellij.openapi.diagnostic.FrequentEventDetector.eventHappened(FrequentEventDetector.java:61)
    at com.intellij.ide.IdeEventQueue.postEvent(IdeEventQueue.java:988)
    at java.awt.EventQueue.invokeLater(EventQueue.java:1078)
    at javax.swing.SwingUtilities.invokeLater(SwingUtilities.java:1267)
    at com.intellij.util.containers.TransferToEDTQueue.schedule(TransferToEDTQueue.java:140)
    at com.intellij.util.containers.TransferToEDTQueue.scheduleUpdate(TransferToEDTQueue.java:135)
    at com.intellij.util.containers.TransferToEDTQueue.offer(TransferToEDTQueue.java:113)
    at com.intellij.codeInsight.daemon.impl.HighlightingSessionImpl.queueHighlightInfo(HighlightingSessionImpl.java:135)
    at com.intellij.codeInsight.daemon.impl.DefaultHighlightInfoProcessor.infoIsAvailable(DefaultHighlightInfoProcessor.java:153)
    at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass$5.run(GeneralHighlightingPass.java:354)
    at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.analyzeByVisitors(GeneralHighlightingPass.java:397)
    at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.access$300(GeneralHighlightingPass.java:64)
    at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass$6.run(GeneralHighlightingPass.java:403)
    at com.intellij.codeInsight.daemon.impl.DefaultHighlightVisitor.analyze(DefaultHighlightVisitor.java:87)
    at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.analyzeByVisitors(GeneralHighlightingPass.java:400)
    at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.access$300(GeneralHighlightingPass.java:64)
    at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass$6.run(GeneralHighlightingPass.java:403)
    at com.intellij.codeInsight.daemon.impl.RefCountHolder.analyze(RefCountHolder.java:318)
    at com.intellij.codeInsight.daemon.impl.analysis.HighlightVisitorImpl.analyze(HighlightVisitorImpl.java:173)
    at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.analyzeByVisitors(GeneralHighlightingPass.java:400)
    at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.collectHighlights(GeneralHighlightingPass.java:388)
    at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.collectInformationWithProgress(GeneralHighlightingPass.java:230)
    at com.intellij.codeInsight.daemon.impl.ProgressableTextEditorHighlightingPass.doCollectInformation(ProgressableTextEditorHighlightingPass.java:86)
    at com.intellij.codeHighlighting.TextEditorHighlightingPass.collectInformation(TextEditorHighlightingPass.java:61)
    at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass$1$1.run(PassExecutorService.java:380)
    at com.intellij.openapi.application.impl.ApplicationImpl.tryRunReadAction(ApplicationImpl.java:1154)
    at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass$1.run(PassExecutorService.java:371)
    at com.intellij.openapi.progress.ProgressManager.executeProcessUnderProgress(ProgressManager.java:209)
    at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:212)
    at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.doRun(PassExecutorService.java:368)
    at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.run(PassExecutorService.java:344)
    at com.intellij.concurrency.JobLauncherImpl$VoidForkJoinTask.exec(JobLauncherImpl.java:193)
    at jsr166e.ForkJoinTask.doExec(ForkJoinTask.java:260)
    at jsr166e.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:858)
    at jsr166e.ForkJoinPool.scan(ForkJoinPool.java:1687)
    at jsr166e.ForkJoinPool.runWorker(ForkJoinPool.java:1642)
    at jsr166e.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:109)

Cancelling build takes a long time

Killing a build by pressing the "x" down at the bottom of the display takes a long time and doesn't seem to kill the running ghc when in the middle of cabal build. haskell-src-exts is a good project for testing this, especially builds after altering InternalParser.ly.

Automate the build process

Adding a new ticket for this issue to get some way of tracing the decision in the future.

Yes, I think we should remove the files! I'm a bit worried about shellscripts though, they probably cause trouble for anyone using windows, are not very good for avoiding spurious regeneration in the build process, and I'm not sure how well they integrate with whatever the latest build tool for Java is called.

I was looking at Travis for continuous integration the other day and the Java support seems good. It would probably be good to switch to a build system that is supported by Travis. Maven, ant and some other is supported. I don't know any of them so I have no opinion on which one is better for our purposes, but that would supposedly give us regeneration of gen/ when it is necessary and avoid it in other cases. I have an option called "Generate ant build" in my build menu, but I can't tell if that would try to build the project with ant or generate a ant-file that I could use for building.

There is a tab called "Dependencies" in the project settings under module, and another one called Artifacts where you can specify something that look like dependencies. It might not be worth the hassle if we have an ant/maven/etc file that works though, I have no idea.

Don't feel that you shouldn't commit what you currently have though, that's a good start. Just reassign the ticket to me if you're swamped and give me a hint about what path we should choose. If it's just up to me I would go with ant because it bears some resemblance with Make, for better or worse, and the other options I have no idea about.

HaskForce steals focus from Java projects

With two projects open, one Haskell project and one Java project, I lose focus/the cursor in the Java project after opening a diff in the changes panel in the Java project sometimes.

My guess is that we are missing an early return if the object we're working with is not a Haskell File, but I have no specific information on where it might be.

Add SDK

Working on the Haskell SDK discovery. First I'll start with Mac OS X, then I'll get it working on Windows and Linux.

Fix size/alignment of components in Configurables.

The dialog boxes (External Haskell Tools, Haskell Compiler, source files typically named HaskellSomethingConfigurable) currently put all elements at full width in the middle of panel. Elements should be of reasonable size for their type and sensibly aligned in the right place of the box.

The comment on commit d2222c0 outlines possible ways of implementing this ticket. Future updates will need more elements in the dialog boxes so the solution needs to be maintainable.

Missing build dependencies in IntelliJ project

After updating my tree with the fix for #18 and doing "Prepare plugin for release" and installing/restarting I just got a spinning wheel and "Loading.." for the dialog boxes in preferences. I did Build->Rebuild project and another release and things worked again.

I suspect we're missing a dependency on something somewhere, but I'm not sure on what.

Strings should allow escaped double quotes

Unfortunately, it seems the resolution for #10 means that escaped double quotes result in a parse error now. I will be adding a failing test case and working on the resolution for this.

New project

I just created a new Haskell project in the hlint sources and all directories were missing. I created a new project and the directories appeared, but I could not build the project. When I removed the module in project settings and added it back I could build things. We are probably missing some project/module importer glue somewhere.

Parser consumes too much in do block

I'm pretty sure the problem here either lies in HaskellParserUtilBase.stateHackMess or HaskellParserWrapper.increaseRbraceDebt. I'm having trouble deciphering the logic in those methods.

The line runGhcModT' :: IOish m ... is being considered part of the do block and parsed as an exp instead of a gendecl.

module Layout00021 where

runGhcModT :: IOish m
           => Options
           -> GhcModT m a
           -> m (Either GhcModError a, GhcModLog)
runGhcModT opt action = do
    env <- liftBase $ newGhcModEnv opt =<< getCurrentDirectory
    first (fst <$>) <$> (runGhcModT' env defaultState $ do
        dflags <- getSessionDynFlags
        defaultCleanupHandler dflags $ do
            initializeFlagsWithCradle opt (gmCradle env)
            action)

runGhcModT' :: IOish m
           => GhcModEnv
           -> GhcModState
           -> GhcModT m a
           -> m (Either GhcModError (a, GhcModState), GhcModLog)
runGhcModT' r s a = do
  (res, w') <-
      flip runReaderT r $ runJournalT $ runErrorT $
        runStateT (unGhcModT $ initGhcMonad (Just ghcLibDir) >> a) s
  return (res, w')

Parser fails for record syntax

Not sure why, but the Grammar Kit parser fails with 'method' unexpected for the following source -

module Foo where

getOAuthTokens :: Config -> SamlAssertion -> IO (OAuthToken, OAuthTokenSecret)
getOAuthTokens config assertion = do
    manager <- newManager def
    initReq <- parseUrl samlUrl
    let headers = "OAuth oauth_consumer_key=\"" <> consumerKey config <> "\""
    let body = [("saml_assertion", assertion)]
    let req = urlEncodedBody body $ initReq
                -- 'method' unexpected
                { method="POST"
                , requestHeaders=[("Authorization", headers)]
                }
    response <- runResourceT $ httpLbs req manager
    let result = parseBody . responseBody $ response
    let get k = lookup k result
    let maybeTokens = Just (,) `ap` get "oauth_token"
                               `ap` get "oauth_token_secret"
    return $ fromMaybe
        -- TODO: Better error handling, possibly use Either.
        (error $ "Tokens not found in response: " ++ show result)
        maybeTokens

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.