xmonad-contrib 提示:在特定工作区执行终端提示?
xmonad-contrib Prompt: Execute terminal prompt in a particular workspace?
我最近决定通过 Stack 从源代码构建 XMonad 以进行自定义配置。先声明一下,我对 Haskell 没有太多经验。
我的 OS 是 Linux - Arch.
设置
我正在尝试使用 xmonad-contrib 中的 XMonad.Prompt
包来启动一些应用程序。
(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
在现有终端中打开并且不提供设置 window 名称的选项,所以我最初无法使用 ManageHook
检测 window 命名并将其转移到正确的工作区,就像我对 Mozilla Firefox 等应用程序所做的那样:(https://hackage.haskell.org/package/xmonad-0.15/docs/XMonad-ManageHook.html)
myManageHook = composeAll
[
...
, title =? "Mozilla Firefox" -> (doShift !! myWorkspaces 1)
...
]
我已经尝试将 window 名称设置为使用 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
的源代码(来自 XMonad.Util.Run
),在我看来它需要 2 个字符串参数:第一个是选项列表,""
在在 manPrompt
的情况下(即默认情况下为空白),第二个是 运行 的命令,在 manPrompt
的情况下是 "man "
。这些都在默认终端中得到 运行(对我来说很敏捷)。
(文档: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)
我可以做些什么来修改 manPrompt
或 runInTerm
以便我可以指定 manPrompt
生成的终端在哪个工作区中生成?或者有没有其他任何人知道实现我不知道的期望行为的方法?
编辑#1
根据最近回答的建议,我正在尝试将 manPrompt
的代码从 XMonad.Actions.SpawnOn
修补为 运行 spawnOn
,而不是 runInTerm
.
(https://hackage.haskell.org/package/xmonad-contrib-0.13/docs/XMonad-Actions-SpawnOn.html)
这是我现在拥有的:
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 数据类型,但我不明白...如果调用 spawnOn
的正确方法是 spawnOn <workspaceId> <command>
,如何我可以像上面那样将 String
bash 命令作为 <command>
传递给函数吗?
编辑 #2 -- 解决方案 #1
我目前的解决方案是使用 XMonad.Prompt.Man
的自定义补丁,manPrompt
如下所示:
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
相同的文本对齐问题,当在 windows 之间移动终端时具有不同布局的工作区。 (我在我尝试过的下的原始post中提到了这些。)
为了更好地解释“文本对齐问题”的含义,我在此处提供了一个屏幕截图:https://ibb.co/vxjcKZh
(这张截图是在一个布局被压扁的工作区上调用提示的结果。然后我将注意力转移到产生联机帮助页的工作区,它应该是全屏的,但你可以看到,文本没有填满整个终端 window;这是因为 man
命令 运行 当 window 大小被压缩时。)
有什么方法可以在终端 window 生成后以某种方式刷新文本?
runInTerm
的调整版本确实很适合这里。 runInTerm
is defined as:
unsafeRunInTerm, runInTerm :: String -> String -> X ()
unsafeRunInTerm options command = asks (terminal . config) >>= \t ->
unsafeSpawn $ t ++ " " ++ options ++ " -e " ++ command
runInTerm = unsafeRunInTerm
unsafeSpawn
又是 XMonad.Actions.SpawnOn
中 spawn
from XMonad.Core
. There is a spawnOn
变体的别名,除了命令 [=53] 外,它还需要一个 WorkspaceId
=].似乎使用 spawnOn
定义自定义 runInTerm
就足以得到你想要的东西。
在您的编辑尝试中,mkXPrompt
的最后一个参数应该是 String -> X ()
函数,而不是 X ()
动作。 String
参数代表用户在提示中选择的完成,在您的情况下,这将是 man
的参数。在manPrompt
的原始实现中,String -> 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
,因为传递字符串将不起作用。我还假设此函数被添加到 [= 的修改副本之类的东西中39=],因为 Man
构造函数和 getMans
函数均未由模块的原始版本导出。)
我最近决定通过 Stack 从源代码构建 XMonad 以进行自定义配置。先声明一下,我对 Haskell 没有太多经验。 我的 OS 是 Linux - Arch.
设置
我正在尝试使用 xmonad-contrib 中的 XMonad.Prompt
包来启动一些应用程序。
(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
在现有终端中打开并且不提供设置 window 名称的选项,所以我最初无法使用 ManageHook
检测 window 命名并将其转移到正确的工作区,就像我对 Mozilla Firefox 等应用程序所做的那样:(https://hackage.haskell.org/package/xmonad-0.15/docs/XMonad-ManageHook.html)
myManageHook = composeAll
[
...
, title =? "Mozilla Firefox" -> (doShift !! myWorkspaces 1)
...
]
我已经尝试将 window 名称设置为使用 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
的源代码(来自 XMonad.Util.Run
),在我看来它需要 2 个字符串参数:第一个是选项列表,""
在在 manPrompt
的情况下(即默认情况下为空白),第二个是 运行 的命令,在 manPrompt
的情况下是 "man "
。这些都在默认终端中得到 运行(对我来说很敏捷)。
(文档: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)
我可以做些什么来修改 manPrompt
或 runInTerm
以便我可以指定 manPrompt
生成的终端在哪个工作区中生成?或者有没有其他任何人知道实现我不知道的期望行为的方法?
编辑#1
根据最近回答的建议,我正在尝试将 manPrompt
的代码从 XMonad.Actions.SpawnOn
修补为 运行 spawnOn
,而不是 runInTerm
.
(https://hackage.haskell.org/package/xmonad-contrib-0.13/docs/XMonad-Actions-SpawnOn.html)
这是我现在拥有的:
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 数据类型,但我不明白...如果调用 spawnOn
的正确方法是 spawnOn <workspaceId> <command>
,如何我可以像上面那样将 String
bash 命令作为 <command>
传递给函数吗?
编辑 #2 -- 解决方案 #1
我目前的解决方案是使用 XMonad.Prompt.Man
的自定义补丁,manPrompt
如下所示:
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
相同的文本对齐问题,当在 windows 之间移动终端时具有不同布局的工作区。 (我在我尝试过的下的原始post中提到了这些。)
为了更好地解释“文本对齐问题”的含义,我在此处提供了一个屏幕截图:https://ibb.co/vxjcKZh
(这张截图是在一个布局被压扁的工作区上调用提示的结果。然后我将注意力转移到产生联机帮助页的工作区,它应该是全屏的,但你可以看到,文本没有填满整个终端 window;这是因为 man
命令 运行 当 window 大小被压缩时。)
有什么方法可以在终端 window 生成后以某种方式刷新文本?
runInTerm
的调整版本确实很适合这里。 runInTerm
is defined as:
unsafeRunInTerm, runInTerm :: String -> String -> X ()
unsafeRunInTerm options command = asks (terminal . config) >>= \t ->
unsafeSpawn $ t ++ " " ++ options ++ " -e " ++ command
runInTerm = unsafeRunInTerm
unsafeSpawn
又是 XMonad.Actions.SpawnOn
中 spawn
from XMonad.Core
. There is a spawnOn
变体的别名,除了命令 [=53] 外,它还需要一个 WorkspaceId
=].似乎使用 spawnOn
定义自定义 runInTerm
就足以得到你想要的东西。
在您的编辑尝试中,mkXPrompt
的最后一个参数应该是 String -> X ()
函数,而不是 X ()
动作。 String
参数代表用户在提示中选择的完成,在您的情况下,这将是 man
的参数。在manPrompt
的原始实现中,String -> 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
,因为传递字符串将不起作用。我还假设此函数被添加到 [= 的修改副本之类的东西中39=],因为 Man
构造函数和 getMans
函数均未由模块的原始版本导出。)