2

我最近决定通过 Stack 从源代码构建 XMonad 以进行自定义配置。让我先说我没有大量使用 Haskell 的经验。我的操作系统是 Linux - Arch。

设置

我正在尝试使用XMonad.Promptxmonad-contrib 中的包来启动一些应用程序。(https://hackage.haskell.org/package/xmonad-contrib-0.13/docs/XMonad-Prompt.html

目前,我使用的一个提示是,它使用默认终端中提供的参数XMonad.Prompt.Man启动程序(我默认的终端是 Alacritty)。man(文档:https ://hackage.haskell.org/package/xmonad-contrib-0.13/docs/XMonad-Prompt-Man.html )(来源:https ://hackage.haskell.org/package/xmonad-contrib- 0.13/docs/src/XMonad-Prompt-Man.html )

我不明白的是如何使用此提示将终端启动到工作区 2,我希望在其中打开所有联机帮助页。

提示目前的工作方式:

我在 中设置了一个键绑定xmonad.hs,如下所示:

...
, ("M-C-m", manPrompt myPromptConfig)
...

这可以按照文档所说的方式工作,但是联机帮助页始终在当前工作区中打开,而不是在我希望它们打开的工作区 2 中。

我试过的

因为man在现有终端中打开并且不提供设置窗口名称的选项,所以我最初无法ManageHook用于检测窗口名称并将其转移到正确的工作区,就像我对 Mozilla Firefox 之类的应用程序所做的那样:(https: //hackage.haskell.org/package/xmonad-0.15/docs/XMonad-ManageHook.html )

myManageHook = composeAll
    [
    ...
    , title =? "Mozilla Firefox" -> (doShift !! myWorkspaces 1)
    ...
    ]

我尝试使用 Alacritty 的选项将窗口名称设置为硬编码的名称,但这只会在终端生成并且已经在当前布局上调用--title之后才移动终端,导致终端移动到不同的文本对齐方式不正确man具有不同布局的工作区。

我认为适当的解决方案可能需要修改XMonad.Prompt.Man.

查看源代码XMonad.Prompt.Man,我发现这一行可能有助于更改(第 60-63 行):(https://hackage.haskell.org/package/xmonad-contrib-0.13/docs/src/XMonad-Prompt -Man.html )

manPrompt :: XPConfig -> X()
manPrompt c = do         -- NOTE FROM ME: getMans and manCompl are functions defined elsewhere in the file that are not relevant here
    mans <- io getMans
    mkXPrompt Man c (manCompl c mans) $ runInTerm "" . (++) "man "
    

查看runInTerm(from XMonad.Util.Run) 的源代码,在我看来它需要 2 个字符串 args:第一个是选项列表,""manPrompt(即默认为空白) 的情况下,第二个是要运行的命令,"man "在的情况manPrompt。这些都在默认终端中运行(对我来说是 Alacritty)。(文档:https ://hackage.haskell.org/package/xmonad-contrib-0.16/docs/XMonad-Util-Run.html )(来源:https ://hackage.haskell.org/package/xmonad-contrib- 0.16/docs/src/XMonad.Util.Run.html#runInTerm )

我可以做些什么来修改manPromptrunInTerm指定终端在哪个工作区中manPrompt生成?或者有没有其他人知道实现我不知道的期望行为的方法?

编辑#1

在最近的答案的建议下,我试图修补代码以从manPrompt运行,而不是. (https://hackage.haskell.org/package/xmonad-contrib-0.13/docs/XMonad-Actions-SpawnOn.htmlspawnOnXMonad.Actions.SpawnOnrunInTerm

这是我现在所拥有的:

manPrompt :: XPConfig -> WorkspaceId -> String -> X ()
manPrompt promptConfig workspaceId terminalArgs = do
    mans <- io getMans
    mkXPrompt (showXPrompt "man ") promptConfig (manCompl promptConfig mans) $ spawnOn (workspaceId) $ (myTerminal) ++ " " ++ (terminalArgs) ++ " -e man "

但是,这不会编译,导致错误:

 xmonad.hs:248:78: error:
    * Couldn't match expected type `String -> X ()'
                  with actual type `X ()'
    * In the second argument of `($)', namely
        `spawnOn (workspaceId)
           $ (myTerminal) ++ " " ++ (terminalArgs) ++ " -e man "'
      In a stmt of a 'do' block:
        mkXPrompt
          (showXPrompt "man ") promptConfig (manCompl promptConfig mans)
          $ spawnOn (workspaceId)
              $ (myTerminal) ++ " " ++ (terminalArgs) ++ " -e man "
      In the expression:
        do mans <- io getMans
           mkXPrompt
             (showXPrompt "man ") promptConfig (manCompl promptConfig mans)
             $ spawnOn (workspaceId)
                 $ (myTerminal) ++ " " ++ (terminalArgs) ++ " -e man "
    |
248 |   mkXPrompt (showXPrompt "man ") promptConfig (manCompl promptConfig mans) $ spawnOn (workspaceId) $ (myTerminal) ++ " " ++ (terminalArgs) ++ " -e man "
    |                                                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                        

我认为这个问题是由于我未能正确掌握 Haskell 数据类型,但我不明白......如果调用的正确方法spawnOnspawnOn <workspaceId> <command>,我如何将Stringbash 命令传递给函数<command>,就像上面一样?

编辑#2——解决方案#1

我目前的解决方案是使用一个自定义补丁XMonad.Prompt.ManmanPrompt它看起来像下面这样:

manPrompt :: XPConfig -> WorkspaceId -> String -> X ()
manPrompt promptConfig workspaceId terminalArgs = do
    mans <- io getMans
    mkXPrompt Man promptConfig (manCompl promptConfig mans) $
    \input -> spawnOn workspaceId $ myTerminal ++ " " ++ terminalArgs ++ " -e man " ++ input

我猜这可以编译并且可以工作,但似乎仍然会导致与在具有不同布局的工作区之间移动终端窗口时spawnOn相同的文本对齐问题。(我在我尝试过doShift的原始帖子中提到了这些。)

为了更好地解释“文本对齐问题”的含义,我在此处添加了一个屏幕截图:https ://ibb.co/vxjcKZh将注意力集中在生成联机帮助页的工作区上,它应该是全屏的,但是您可以看到,文本不会填满整个终端窗口;这是因为该man命令在窗口大小被压缩时运行。)

有没有办法在终端窗口产生后以某种方式刷新终端窗口中的文本?

4

1 回答 1

1

调整后的版本runInTerm确实很适合这里。runInTerm 定义为

unsafeRunInTerm, runInTerm :: String -> String -> X ()
unsafeRunInTerm options command = asks (terminal . config) >>= \t ->
    unsafeSpawn $ t ++ " " ++ options ++ " -e " ++ command
runInTerm = unsafeRunInTerm

unsafeSpawn又是spawnfromXMonad.Core的别名。它有一个spawnOn变体,XMonad.Actions.SpawnOn其中WorkspaceId除了要运行的命令之外还需要一个。似乎使用spawnOn定义自定义runInTerm就足以得到你想要的。


在您尝试编辑时,最后一个参数mkXPrompt应该是一个String -> X ()函数,而不是一个X ()动作。该String参数代表用户在提示中选择的完成,在您的情况下,它将是man. 在 的原始实现中manPromptString -> X ()函数是:

runInTerm "" . (++) "man "

或者,以一种可以说更清晰的方式重新表述它:

\completion -> runInTerm "" ("man " ++ completion)

manPrompt可以相应地调整:

manPromptOn :: XPConfig -> WorkspaceId -> String -> X ()
manPromptOn promptConfig workspaceId terminalArgs = do
    mans <- io getMans
    mkXPrompt Man promptConfig (manCompl promptConfig mans) $
        \completion -> spawnOn workspaceId $
            myTerminal ++ " " ++ terminalArgs ++ " -e man " ++ completion

(请注意,我另外将第一个参数更改为mkXPrompt,因为传递字符串不起作用。我还假设此函数被添加到模块的修改副本XMonad.Prompt.Man类的东西中,因为Man构造函数和getMans函数都不是t 由模块的原始版本导出。)

于 2022-03-05T01:23:47.697 回答