Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve feedback when plugin code throws exception #96

Open
saep opened this issue Jan 31, 2022 · 6 comments
Open

Improve feedback when plugin code throws exception #96

saep opened this issue Jan 31, 2022 · 6 comments

Comments

@saep
Copy link
Member

saep commented Jan 31, 2022

No description provided.

@saep
Copy link
Member Author

saep commented Jan 31, 2022

@isovector wrote in #95 :

One side effect of this patch is that unhandled exceptions no longer end up in the log --- plugins just mysteriously stop working.

Is this actually true? I've written and incredibly useful plugin below and I receive log messages and I see error messages in neovim.

When calling the command :ThrowExceptionCommand:

[Socket Reader : DEBUG] Received: ObjectArray [ObjectInt 0,ObjectInt 2,ObjectString "ThrowExceptionCommand:command",ObjectArray [ObjectArray [],ObjectInt 0]]
[Socket Reader : DEBUG] Executing stateful function with ID: Just 2
[EventHandler : DEBUG] Sending: Response 2 (Left (ObjectBinary "ErrorResult throwExceptionFunction (ObjectArray [ObjectInt 1,ObjectBinary \"Simulate neovim exception\"])"))

image

When calling the function with :call ThrowExceptionFunction():

[Socket Reader : DEBUG] Received: ObjectArray [ObjectInt 2,ObjectString "ThrowExceptionFunction:function",ObjectArray [ObjectArray []]]
[Socket Reader : DEBUG] Executing stateful function with ID: Nothing
[EventHandler : DEBUG] Sending: Request (Request {reqMethod = F "nvim_err_writeln", reqId = 9, reqArgs = [ObjectBinary "ErrorResult throwExceptionFunction (ObjectArray [ObjectInt 1,ObjectBinary \"Simulate neovim exception\"])"]})
[Socket Reader : DEBUG] Received: ObjectArray [ObjectInt 1,ObjectInt 9,ObjectNil,ObjectNil]

image

When an autocmd is executed:

[Socket Reader : DEBUG] Received: ObjectArray [ObjectInt 2,ObjectString "ThrowExceptionAutoCommand",ObjectArray []]
[Socket Reader : DEBUG] Received: ObjectArray [ObjectInt 2,ObjectString "ThrowExceptionAutoCommand",ObjectArray []]
[Socket Reader : DEBUG] Executing stateful function with ID: Nothing
[Socket Reader : DEBUG] Executing stateful function with ID: Nothing
[EventHandler : DEBUG] Sending: Request (Request {reqMethod = F "nvim_err_writeln", reqId = 8, reqArgs = [ObjectBinary "ErrorResult throwExceptionFunction (ObjectArray [ObjectInt 1,ObjectBinary \"Simulate neovim exception\"])"]})
[EventHandler : DEBUG] Sending: Request (Request {reqMethod = F "nvim_err_writeln", reqId = 8, reqArgs = [ObjectBinary "ErrorResult throwExceptionFunction (ObjectArray [ObjectInt 1,ObjectBinary \"Simulate neovim exception\"])"]})

image

{-# LANGUAGE OverloadedStrings #-}
module Neovim.Example.Plugin.Throws where

import Neovim
import UnliftIO (throwIO)

throwExceptionFunction :: Neovim env ()
throwExceptionFunction = throwIO $ ErrorResult
        "throwExceptionFunction"
        (toObject (1 :: Int32, "Simulate neovim exception" :: String))

throwExceptionCommand :: CommandArguments -> Neovim env ()
throwExceptionCommand _ = throwExceptionFunction

throwExceptionAutoCommand :: Neovim env ()
throwExceptionAutoCommand = throwExceptionFunction
{-# LANGUAGE TemplateHaskell, OverloadedStrings #-}
module Neovim.Example.Plugin ( plugin ) where

import Neovim.Example.Plugin.Throws (throwExceptionAutoCommand, throwExceptionCommand, throwExceptionFunction)

plugin :: Neovim () NeovimPlugin
plugin = do
    wrapPlugin Plugin
        { environment = ()
        , exports =
            [ $(command' 'throwExceptionCommand) [CmdBang]
            , $(function' 'throwExceptionFunction) Async
            , $(autocmd 'throwExceptionAutoCommand) "FileType" Async def{acmdPattern = "vim"}
            ]
        }

@isovector
Copy link
Contributor

isovector commented Jan 31, 2022

I experienced this issue when calling vim from an async thread! Maybe I am confused that it never used to report exceptions in async threads?

I can put together an mvp later today

@saep
Copy link
Member Author

saep commented Jan 31, 2022

The following code swallows exceptions and if the second to last line is not commented, and exception is visible.

neovimAsync :: (MonadUnliftIO m) => m a -> m (Async a)
neovimAsync m =
  withRunInIO $ \lower ->
    liftIO $ async $ lower m


throwExceptionFunctionAsync :: Neovim env Bool
throwExceptionFunctionAsync = do
  spawned <- neovimAsync $ throwExceptionFunction
  -- liftIO $ waitAnyCancel [spawned]
  pure True

I barely ever program in Haskell, but to me it seems that this is kind of expected behavior from the async library?

@isovector
Copy link
Contributor

Yeah, might be. Perhaps it's worth adding an async helper to the library that deals with this --- rather than doing the whole withRunInIO dance. Would you be interested in a PR?

@saep
Copy link
Member Author

saep commented Feb 1, 2022

Sure!

@saep
Copy link
Member Author

saep commented Feb 1, 2022

Or maybe just use: https://hackage.haskell.org/package/unliftio-0.2.20.1/docs/UnliftIO-Async.html
It's already a dependency and used internally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants