yi-editor / yi

The Haskell-Scriptable Editor
GNU General Public License v2.0
1.51k stars 203 forks source link

‘reload’ doesn't restart Yi #515

Closed Fuuzetsu closed 10 years ago

Fuuzetsu commented 10 years ago

On my system, calling reload hangs Yi for a while (it's probably compiling config) and then kills it. I'd expect Yi to get restarted at this point but it doesn't.

32-bit Linux.

Does it work for anyone? Did it ever?

Fuuzetsu commented 10 years ago

160 is somewhat related.

ethercrow commented 10 years ago

:reload using yi-vim2 config works for me on 64bit gentoo and 64bit os x, but M-x reload using yi-simple config shows error: WontCompile [GhcError {errMsg = "Could not find moduleYi.Prelude'\nIt is a member of the hidden package yi-0.6.7.0'."}]

Fuuzetsu commented 10 years ago

Hm, I just tried :reload with vim config and it worked for the basic case while with my emacs config I have the effect described in the OP.

Regarding that compile error, it sounds like you have an old install there, I just checked and any Yi.Prelude mentions were removed from any relevant Haskell files.

codygman commented 10 years ago

I had the same issue and ran Yi with --debug/tailed it:

cody@cody-G46VW:~/source/yi/yi/src$ tail -f ~/.yi.dbg 
Tue, 11 Mar 2014 04:40:09 UTC ThreadId 3 >>> interactively
Tue, 11 Mar 2014 04:40:09 UTC ThreadId 3 <<<
Tue, 11 Mar 2014 04:40:09 UTC ThreadId 3 >>> interactively
Tue, 11 Mar 2014 04:40:09 UTC ThreadId 3 <<<
Tue, 11 Mar 2014 04:40:09 UTC ThreadId 10 time to render
Tue, 11 Mar 2014 04:40:09 UTC ThreadId 10 refreshing screen.
Tue, 11 Mar 2014 04:40:09 UTC ThreadId 10 startXs: [] 0 []
Tue, 11 Mar 2014 04:40:09 UTC ThreadId 10 time to render
Tue, 11 Mar 2014 04:40:09 UTC ThreadId 10 refreshing screen.
Tue, 11 Mar 2014 04:40:09 UTC ThreadId 10 startXs: [] 0 []
Tue, 11 Mar 2014 04:40:26 UTC ThreadId 9 pending events: 
Tue, 11 Mar 2014 04:40:26 UTC ThreadId 9 >>> interactively
Tue, 11 Mar 2014 04:40:28 UTC ThreadId 9 <<<
Tue, 11 Mar 2014 04:40:28 UTC ThreadId 9 pending events: 
Tue, 11 Mar 2014 04:40:28 UTC ThreadId 9 >>> interactively
Tue, 11 Mar 2014 04:40:28 UTC ThreadId 9 <<<
Tue, 11 Mar 2014 04:40:28 UTC ThreadId 9 pending events: 
Tue, 11 Mar 2014 04:40:28 UTC ThreadId 9 >>> interactively
Tue, 11 Mar 2014 04:40:28 UTC ThreadId 9 <<<
Tue, 11 Mar 2014 04:40:28 UTC ThreadId 10 time to render
Tue, 11 Mar 2014 04:40:28 UTC ThreadId 10 refreshing screen.
Tue, 11 Mar 2014 04:40:28 UTC ThreadId 10 startXs: [0] 17 []
Tue, 11 Mar 2014 04:40:28 UTC ThreadId 10 time to render
Tue, 11 Mar 2014 04:40:28 UTC ThreadId 10 refreshing screen.
Tue, 11 Mar 2014 04:40:28 UTC ThreadId 10 startXs: [0] 17 []
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 9 pending events: 
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 9 >>> interactively
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 9 <<<
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 10 time to render
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 10 refreshing screen.
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 10 startXs: [0] 17 []
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 9 pending events: 
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 9 >>> interactively
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 9 <<<
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 10 time to render
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 10 refreshing screen.
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 10 startXs: [0] 17 []
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 9 pending events: 
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 9 >>> interactively
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 9 <<<
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 10 time to render
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 10 refreshing screen.
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 10 startXs: [0] 17 []
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 9 pending events: 
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 9 >>> interactively
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 9 <<<
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 10 time to render
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 10 refreshing screen.
Tue, 11 Mar 2014 04:40:29 UTC ThreadId 10 startXs: [0] 17 []
Tue, 11 Mar 2014 04:40:31 UTC ThreadId 9 pending events: 
Tue, 11 Mar 2014 04:40:31 UTC ThreadId 9 >>> interactively
Tue, 11 Mar 2014 04:40:32 UTC ThreadId 9 errorEditor: Maybe.fromJust: Nothing

Then the list of places fromJust is used:

cody@cody-G46VW:~/source/yi/yi/src$ rgrep fromJust | grep -i -v vim
library/Yi/UI/Pango/Control.hs:import Data.Maybe (maybe, fromJust, fromMaybe)
library/Yi/UI/Pango/Control.hs:--      (%=) windowsA (fromJust . PL.move winIdx)
library/Yi/Editor.hs:swapWinWithFirstE = (%=) windowsA (swapFocus (fromJust . PL.moveTo 0))
library/Yi/Editor.hs:          Just ws' -> PL.insertLeft (ws ^. PL.focus) (fromJust $ PL.moveTo 0 ws')
library/Yi/Editor.hs:            assign tabsA (fromJust $ PL.moveTo tabIndex ts)
library/Yi/Editor.hs:            (%=) windowsA (fromJust . PL.moveTo winIndex)
library/Yi/Editor.hs:                      (%=) tabsA $ fromJust . PL.moveTo (pred count)
library/Yi/Editor.hs:                      assign tabsA $ fromJust newTabs
library/Yi/Editor.hs:      then (%=) tabsA (fromJust . PL.deleteLeft)
library/Yi/Editor.hs:      else (%=) windowsA (fromJust . PL.deleteLeft)
library/Yi/MiniBuffer.hs:                        (%=) windowsA (fromJust . PL.find initialWindow)
library/Yi/Dynamic.hs:import Data.Maybe(fromJust)
library/Yi/Dynamic.hs:                Just x -> fromJust $ D.fromDynamic x
library/Yi/Dynamic.hs:  --            Just x -> fromJust $ D.fromDynamic x
library/Yi/Dynamic.hs:                                   Just x -> fromJust $ fromDynamic x
library/Yi/Syntax/Haskell.hs:                      (flip notElem f . tokT . fromJust)
library/Yi/Syntax/Haskell.hs:                       (flip elem f . tokT . fromJust))
library/Shim/Hsinfo.hs:                         ((fst3 . fromJust) storedres `replaceWith` cres))) $
library/Shim/Hsinfo.hs:        ("fromJust","Maybe a -> a"),
library/Shim/Hsinfo.hs:       [("fromJust","Maybe a -> a"),("fromMaybe","a -> Maybe a -> a")]
cody@cody-G46VW:~/source/yi/yi/src$ 

My hunch is that Yi/Dynamic.hs is working with vim for some reason but not emacs, however it's unfounded. I'll be debugging this further later... have to get up for work early :/

alanz commented 10 years ago

I just replaced all of the above instances with lablelled calls to

gfromJust :: [Char] -> Maybe a -> a
gfromJust _info (Just h) = h
gfromJust  info Nothing = error $ "gfromJust " ++ info ++ " Nothing"

And still get

Fri, 21 Mar 2014 12:46:41 UTC ThreadId 558 pending events: 
Fri, 21 Mar 2014 12:46:41 UTC ThreadId 558 >>> interactively
Fri, 21 Mar 2014 12:46:42 UTC ThreadId 558 errorEditor: Maybe.fromJust: Nothing

So it must be in an imported library somewhere

Fuuzetsu commented 10 years ago

Oh, that sucks a whole lot. I'm guessing it's in dyre somewhere such as Config/Dyre/Relaunch.hs:51: masterPath <- fmap fromJust getMasterBinary. I'll try to find some time to investigate this later today.

alanz commented 10 years ago

Yep, getMasterBinary is returning Nothing

On Fri, Mar 21, 2014 at 3:04 PM, Mateusz Kowalczyk <notifications@github.com

wrote:

Oh, that sucks a whole lot. I'm guessing it's in dyre somewhere such as Config/Dyre/Relaunch.hs:51: masterPath <- fmap fromJust getMasterBinary. I'll try to find some time to investigate this later today.

Reply to this email directly or view it on GitHubhttps://github.com/yi-editor/yi/issues/515#issuecomment-38273930 .

alanz commented 10 years ago

I have spent some time digging through this, and it does not make sense.

The bug can be enabled / disabled by switch from the Vim keybindings to the emacs one.

I added some putStrLn to the getValue and putValue calls in System.IO.Storage

With the vim keymap I get the following

yiDriver:about to call wrapMain
withDyreOptions: storing masterBinary as:/home/alanz/.cache/yi/yi-linux-x86_64
System.IO.Storage.putValue :("dyre","masterBinary",Just "/home/alanz/.cache/yi/yi-linux-x86_64")
System.IO.Storage.putValue :("dyre","masterBinary",Just "/home/alanz/.cabal/bin/yi")
System.IO.Storage.putValue :("dyre","forceReconf",Nothing)
System.IO.Storage.putValue :("dyre","denyReconf",Nothing)
System.IO.Storage.putValue :("dyre","debugMode",Nothing)
System.IO.Storage.getValue :("dyre","persistState")
System.IO.Storage.getValue :("dyre","persistState",Nothing,Nothing)
reload about to relaunchWithBinaryState
System.IO.Storage.putValue :("dyre","persistState",Just "/tmp/13788.state")
relaunchWithBinaryState: saved state
relauncMaster, getting masterBinary
System.IO.Storage.getValue :("dyre","masterBinary")
System.IO.Storage.getValue :("dyre","masterBinary",Nothing,Nothing)
System.IO.Storage.getValue :("dyre","masterBinary")
System.IO.Storage.getValue :("dyre","masterBinary",Nothing,Nothing)
System.IO.Storage.getValue :("dyre","persistState")
System.IO.Storage.getValue :("dyre","persistState",Nothing,Nothing)
customExec: (binary,args)=("/home/alanz/.cabal/bin/yi",["--debug","-fpango","/home/alanz/.config/yi/yi.hs","--dyre-state-persist=/tmp/13788.state","--dyre-master-binary=/home/alanz/.cabal/bin/yi"])

With the emacs keymap I get the following

yiDriver:about to call wrapMain
withDyreOptions: storing masterBinary as:/home/alanz/.cache/yi/yi-linux-x86_64
System.IO.Storage.putValue :("dyre","masterBinary",Just "/home/alanz/.cache/yi/yi-linux-x86_64")
System.IO.Storage.putValue :("dyre","masterBinary",Just "/home/alanz/.cabal/bin/yi")
System.IO.Storage.putValue :("dyre","forceReconf",Nothing)
System.IO.Storage.putValue :("dyre","denyReconf",Nothing)
System.IO.Storage.putValue :("dyre","debugMode",Nothing)
System.IO.Storage.getValue :("dyre","persistState")
System.IO.Storage.getValue :("dyre","persistState",Nothing,Nothing)
reload about to relaunchWithBinaryState
System.IO.Storage.putValue :("dyre","persistState",Just "/tmp/14231.state")
relaunchWithBinaryState: saved state
relauncMaster, getting masterBinary
System.IO.Storage.getValue :("dyre","masterBinary")
System.IO.Storage.getValue :("dyre","masterBinary",Nothing,Nothing)

The two Nothing's printed out in getValue are attempts to cast the value to a String and to a FilePath

It seems that in the emacs case trying to reference the return value from getMasterBinary stops everything dead.

Fuuzetsu commented 10 years ago

It seems that the vim case gets

System.IO.Storage.getValue :("dyre","masterBinary")
System.IO.Storage.getValue :("dyre","masterBinary",Nothing,Nothing)

twice, perhaps emacs simply gives up and vim keeps trying until something changes (binary becomes ready or something? Just a guess).

It is quite strange…

alanz commented 10 years ago

No, thats just an artifact of my quickndirty logging. The one is on ontry to the function, the other on exit with result

On Fri, Mar 21, 2014 at 10:07 PM, Mateusz Kowalczyk < notifications@github.com> wrote:

It seems that the vim case gets

System.IO.Storage.getValue :("dyre","masterBinary") System.IO.Storage.getValue :("dyre","masterBinary",Nothing,Nothing)

twice, perhaps emacs simply gives up and vim keeps trying until something changes (binary becomes ready or something? Just a guess).

It is quite strange...

Reply to this email directly or view it on GitHubhttps://github.com/yi-editor/yi/issues/515#issuecomment-38317860 .

benarmston commented 10 years ago

I believe the difference is in whether the reload command is run via execEditorAction. You can test this by starting yi as yi --as vim2 and then:

  1. running the command :reload. This runs the Yi.Boot.reload function directly and should quickly.
  2. running the command :yi reload. This compiles the string "reload" using the functionexecEditorAction and then runs the result.

In case (2) something seems to hang.

Making the following change

diff --git a/yi/src/library/Yi/Keymap/Emacs.hs b/yi/src/library/Yi/Keymap/Emacs.hs
index 1113456..99f60cd 100644
--- a/yi/src/library/Yi/Keymap/Emacs.hs
+++ b/yi/src/library/Yi/Keymap/Emacs.hs
@@ -15,6 +15,7 @@ module Yi.Keymap.Emacs (keymap,
                         completionCaseSensitive
                         ) where

+import {-# source #-} Yi.Boot (reload)
 import Control.Applicative
 import Control.Lens
 import Data.Prototype
@@ -277,5 +278,6 @@ emacsKeys univArg =
                  , char 'r'      ?>>  rectangleFuntions
                  , char 'u'      ?>>! repeatingArg undoB
                  , char 'v'      ?>>! repeatingArg shrinkWinE
+                 , char 'R'      ?>>! reload
                  , optMod ctrl (char 't') >> tabFunctions
                  ]

Would allow testing the same difference in the emacs key bindings. This time C-x R vs M-x reload.

benarmston commented 10 years ago

I was hoping that the following change would fix this. Unfortunately, it doesn't. Something along these lines may work.

diff --git a/yi/src/library/Yi/Eval.hs b/yi/src/library/Yi/Eval.hs
index ed49df0..693dddb 100644
--- a/yi/src/library/Yi/Eval.hs
+++ b/yi/src/library/Yi/Eval.hs
@@ -28,6 +28,7 @@ import Data.Typeable
 import Data.Binary
 import Data.Default
 import qualified Language.Haskell.Interpreter as LHI
+import qualified Language.Haskell.Interpreter.Unsafe as LHI
 import System.Directory(doesFileExist)
 import qualified Data.HashMap.Strict as M

@@ -94,7 +95,7 @@ ghciEvaluator = Evaluator{..} where
     execEditorActionImpl s = do
        contextFile <- Yi.Paths.getEvaluatorContextFilename
        haveUserContext <- io $ doesFileExist contextFile
-       res <- io $ LHI.runInterpreter $ do
+       res <- io $ LHI.unsafeRunInterpreterWithArgs ["-no-user-package-db", "-package-db=.cabal-sandbox/x86_64-linux-ghc-7.6.3-packages.conf.d/"] $ do
            LHI.set [LHI.searchPath LHI.:= []]
            LHI.set [LHI.languageExtensions LHI.:= [LHI.OverloadedStrings,
                                                    LHI.NoImplicitPrelude -- use Yi prelude instead.
benarmston commented 10 years ago

On further investigation the above changes to LHI are unlikely the problem as running the following works :yi insertN "foo".

alanz commented 10 years ago

Applying your patch results in it working for the C-x R variant, but not M-x reload.

I was pretty sure it was related to how it is called, but I am still confused as to the exact point it fails when it does not work, but maybe it is because the IO output gets queued or something.

I suspect there are processes being forked which then violate the Dyre expectations when it is invoked.

Alan

On Sat, Mar 22, 2014 at 3:22 AM, Ben Armston notifications@github.comwrote:

I believe the difference is in whether the reload command is run via execEditorAction. You can test this by starting yi as yi --as vim2 and then:

  1. running the command :reload. This runs the Yi.Boot.reload function directly and should quickly.
  2. running the command :yi reload. This compiles the string "reload" using the functionexecEditorAction and then runs the result.

In case (2) something seems to hang.

Making the following change

diff --git a/yi/src/library/Yi/Keymap/Emacs.hs b/yi/src/library/Yi/Keymap/Emacs.hsindex 1113456..99f60cd 100644--- a/yi/src/library/Yi/Keymap/Emacs.hs+++ b/yi/src/library/Yi/Keymap/Emacs.hs@@ -15,6 +15,7 @@ module Yi.Keymap.Emacs (keymap, completionCaseSensitive ) where +import {-# source #-} Yi.Boot (reload) import Control.Applicative import Control.Lens import Data.Prototype@@ -277,5 +278,6 @@ emacsKeys univArg = , char 'r' ?>> rectangleFuntions , char 'u' ?>>! repeatingArg undoB , char 'v' ?>>! repeatingArg shrinkWinE+ , char 'R' ?>>! reload , optMod ctrl (char 't') >> tabFunctions ]

Would allow testing the same difference in the emacs key bindings. This time C-x R vs M-x reload.

Reply to this email directly or view it on GitHubhttps://github.com/yi-editor/yi/issues/515#issuecomment-38339345 .

benarmston commented 10 years ago

I'm confused as to the exact point it fails too. I've just tested this with yi installed outside of a cabal sandbox. I had the same result as when yi is inside a cabal sandbox: :reload works whilst :yi reload hangs. So I'd say we can rule out Dyre having trouble with sandboxed builds being the root cause.

alanz commented 10 years ago

Just for completeness, I am testing the long way by doing a cabal install each time, no sandbox.

I suspect it is related to some thread related processing in the minibuffer mode, but have not looked at the source for it yet.

On Sat, Mar 22, 2014 at 10:38 AM, Ben Armston notifications@github.comwrote:

I'm confused as to the exact point it fails too. I've just tested this with yi installed outside of a cabal sandbox. I had the same result as when yi is inside a cabal sandbox: :reload works whilst :yi reload hangs. So I'd say we can rule out Dyre having trouble with sandboxed builds being the root cause.

Reply to this email directly or view it on GitHubhttps://github.com/yi-editor/yi/issues/515#issuecomment-38346194 .

ethercrow commented 10 years ago

If all else fails, we can resort to this:

diff --git a/yi/src/library/Yi/Eval.hs b/yi/src/library/Yi/Eval.hs
index ed49df0..b2b20d4 100644
--- a/yi/src/library/Yi/Eval.hs
+++ b/yi/src/library/Yi/Eval.hs
@@ -32,6 +32,7 @@ import System.Directory(doesFileExist)
 import qualified Data.HashMap.Strict as M

 import Yi.Config.Simple.Types
+import {-# source #-} Yi.Boot
 import Yi.Core
 import Yi.File
 import Yi.Hooks
@@ -91,6 +92,7 @@ exists, it is imported unqualified.
 ghciEvaluator :: Evaluator
 ghciEvaluator = Evaluator{..} where
     execEditorActionImpl :: String -> YiM ()
+    execEditorActionImpl "reload" = reload
     execEditorActionImpl s = do
        contextFile <- Yi.Paths.getEvaluatorContextFilename
        haveUserContext <- io $ doesFileExist contextFile
alanz commented 10 years ago

This does have the advantage of solving the problem :)

My 5c, I also think that reload is a very special case.

On Sat, Mar 22, 2014 at 12:27 PM, Dmitry Ivanov notifications@github.comwrote:

If all else fails, we can resort to this:

diff --git a/yi/src/library/Yi/Eval.hs b/yi/src/library/Yi/Eval.hsindex ed49df0..b2b20d4 100644--- a/yi/src/library/Yi/Eval.hs+++ b/yi/src/library/Yi/Eval.hs@@ -32,6 +32,7 @@ import System.Directory(doesFileExist) import qualified Data.HashMap.Strict as M

import Yi.Config.Simple.Types +import {-# source #-} Yi.Boot

import Yi.Core import Yi.File import Yi.Hooks@@ -91,6 +92,7 @@ exists, it is imported unqualified. ghciEvaluator :: Evaluator ghciEvaluator = Evaluator{..} where execEditorActionImpl :: String -> YiM ()+ execEditorActionImpl "reload" = reload

 execEditorActionImpl s = do
    contextFile <- Yi.Paths.getEvaluatorContextFilename
    haveUserContext <- io $ doesFileExist contextFile

Reply to this email directly or view it on GitHubhttps://github.com/yi-editor/yi/issues/515#issuecomment-38347979 .

Fuuzetsu commented 10 years ago

I'll +1 the workaround if everyone gives up on searching for the fault

codygman commented 10 years ago

@alanz when you say:

"My 5c, I also think that reload is a very special case."

I am looking at Yi as a replacement for Emacs (with a more powerful extension language) and was planning to write a lot of extensions for it. For me and others who planned on doing the same, reload would be a very common case unless I misunderstand something.

For reference I got this error while doing this simple Yi extension tutorial:

http://www.nobugs.org/developer/yi/index.html

alanz commented 10 years ago

The special case I mean is that it is pretty much unique in all the commands that would be used, in that it triggers the dynamic reload of the whole thing.

As such, treating it as a special case makes sense, as it is in a class of its own.

So use would be common, the code would only require a single special case.

On Sat, Mar 22, 2014 at 7:49 PM, codygman notifications@github.com wrote:

@alanz https://github.com/alanz when you say:

"My 5c, I also think that reload is a very special case."

I am looking at Yi as a replacement for Emacs and was planning to write a lot of extensions for it. For me and others who planned on doing the same, reload would be a very common case.

Reply to this email directly or view it on GitHubhttps://github.com/yi-editor/yi/issues/515#issuecomment-38358732 .

ethercrow commented 10 years ago

I've committed the workaround for now.