在 GUI 应用程序中处理文件时,如何在文件浏览器中快速打开文件的父目录?

在 GUI 应用程序中处理文件时,如何在文件浏览器中快速打开文件的父目录?

我来自 MacOS 系统,在该系统中,我沉迷于一种特定功能:在(几乎)任何应用程序中处理(几乎)任何文件时,我可以单击显示该文件的窗口的标题栏,然后打开文件系统中该文件的父文件夹。

在 MacOS 中,这是一项适用于几乎所有应用程序的功能,并且它基于操作系统和(大多数)为该操作系统编写的应用程序之间的相互作用。

右键单击标题我可以访问文档的父文件夹

单击第二次,我将看到包含该文件的文件夹窗口,其中文件本身突出显示

我想在 Linux 系统上有类似的东西(我使用 Mint,带有 Cinnamon 桌面环境)。

我知道也许我需要编写一些脚本,并且可能描述了部分解决方案在这个 U&L 问题/答案中。仍然缺少的是获取文件路径的方法。

因此,我需要的最少功能是(快速)获取我正在可视化的文档的文件路径,同时我处于打开文档窗口的 GUI 应用程序中。

感谢您的任何见解。

答案1

请检查在由另一个应用程序打开的文件上打开文件资源管理器。我是这个问题的OP。菜单的答案是被接受的。这里是完整的解决方案。但是,要了解其工作原理,您必须彻底阅读所引用的帖子。

创建以下脚本(为其提供适当的权限)并将其绑定到键盘快捷键(我已将其绑定到Super key + O),假设脚本名称为open-file-path.sh。现在,当您在 evince(它具有单个窗口的单个进程,并且可以通过命令找到文件的路径ps)之类的 gui 应用程序上使用键盘快捷键并打开某些文件时,该文件很可能会在文件资源管理器中打开。

#!/bin/bash

WINDOW_ID=$(xdotool getactivewindow)

PID_OF_ACTIVE_WINDOW=$(xdotool getwindowpid $WINDOW_ID)

CLASS_NAME=$(xprop -id $WINDOW_ID | rg WM_CLASS | cut -d '"' -f2)

if [ "$CLASS_NAME" = "com.github.johnfactotum.Foliate" ]; then
    log=$HOME/.myfoliate.log
    # nemo "$(awk -v var="$WINDOW_ID" '$1 == var {print}' $log | cut -d" " -f3-)"
    nemo "$(grep -oP "$WINDOW_ID $PID_OF_ACTIVE_WINDOW \K.*" $log)"
    exit 1
fi

if [ "$CLASS_NAME" = "libreoffice" ]; then
    log=$HOME/.mylibreoffice.log
    # nemo "$(awk -v var="$WINDOW_ID" '$1 == var {print}' $log | cut -d" " -f3-)"
    nemo "$(grep -oP "$WINDOW_ID $PID_OF_ACTIVE_WINDOW \K.*" $log)"
    exit 1
fi

if [[ "$CLASS_NAME" == @(gl) ]] ; then
    nemo "$(echo '{ "command": ["get_property", "path"] }' | socat - /tmp/mpv-socket | jq -r ".data")"
    exit 1
fi

MY_COMMAND_PATH=$(ps -p $PID_OF_ACTIVE_WINDOW -o command)

# https://stackoverflow.com/q/76028252/1772898
if printf -- '%s\n' "$MY_COMMAND_PATH" | grep -qoP '(file://)?(?<!\w)/(?!usr/).*?\.\w{3,4}+'; then
    nemo "$(printf -- '%s\n' "$MY_COMMAND_PATH" | grep -oP '(file://)?(?<!\w)/(?!usr/).*?\.\w{3,4}+')"
fi

需要明确的是,标准是:

  • 单个进程对应于单个窗口
  • ps可以通过命令找到文件的路径

对于不符合标准的其他应用程序(如 libreoffice、foliate 等),还有一些额外的步骤。即使执行了额外的步骤,他们也会遇到一些问题。如果您使用文件 > 打开应用程序中的选项。您必须双击才能打开该文件。如果这些应用程序公开一些内部 api 来提供文件路径(例如,对于 mpv,我们使用内部 api),则可以解决此问题。

我们先讨论mpv。默认情况下它就会起作用。它符合标准。

  • 单个进程对应于单个窗口
  • ps可以通过命令找到文件的路径

你只需要删除

if [[ "$CLASS_NAME" == @(gl) ]] ; then
    nemo "$(echo '{ "command": ["get_property", "path"] }' | socat - /tmp/mpv-socket | jq -r ".data")"
    exit 1
fi

open-file-path.sh

但就我而言,我做了一些更改,以便始终有一个窗口,这就是我需要此解决方法的原因。

在我关于 mpv 的情况下,你必须创建一个套接字。加入。input-ipc-server=/tmp/mpv-socket$HOME/.config/mpv/mpv.conf然后我们必须为 mpv 可执行文件创建一个包装器。对于桌面应用程序,我们使用该.desktop文件。对于 mpv 来说,是/usr/share/applications/mpv.desktop。由于我们必须编辑它,我喜欢放置它的副本$HOME/.local/share/applications/mpv.desktop,然后编辑该副本。$HOME/.local/share/applications优先于/usr/share/applications.

cp /usr/share/applications/mpv.desktop $HOME/.local/share/applications/mpv.desktop

然后更改以下行$HOME/.local/share/applications/mpv.desktop

TryExec=mpv
Exec=mpv --player-operation-mode=pseudo-gui -- %U

TryExec=/home/ismail/.dotfiles/.resources/bash-scripts/mpv.sh
Exec=/home/ismail/.dotfiles/.resources/bash-scripts/mpv.sh %U

/home/ismail/.dotfiles/.resources/bash-scripts/mpv.sh文件如下所示:

#!/bin/bash

socat_to_mpv() {
    socat - "/tmp/mpv-socket"
}

if pgrep -x mpv >/dev/null ; then
    wmctrl -x -R gl.mpv
    echo "{ \"command\": [\"loadfile\", \"$1\", \"replace\"] }" | socat_to_mpv
else
    mpv "$1"
fi

这是包装纸代码。我们在启动 mpv 之前和/或之后运行一些代码。

对于 Foliate,在文件$HOME/.local/share/applications/com.github.johnfactotum.Foliate.desktop(我从 复制/usr/share/applications/,如 mpv)中替换Exec为:

Exec=/home/ismail/.dotfiles/.resources/bash-scripts/foliate.sh %U

foliate.sh文件如下所示:

#!/bin/bash

log=$HOME/.myfoliate.log

file=$1

com.github.johnfactotum.Foliate "$1" &
sleep 2

for id in $(xdotool search --onlyvisible --class 'com.github.johnfactotum.Foliate')
do
    winpid=$(xdotool getwindowpid $id)
    winname=$(xdotool getwindowname $id)
    grep -q "^$id $winpid .*" $log || echo "$id $winpid $file" >> $log
done

pid_of_foliate=$(xdotool search --name 'com.github.johnfactotum.Foliate' getwindowpid)

if [ -n "$pid_of_foliate" ]
then
    awk -i inplace -v var="$pid_of_foliate" '$2 == var {print}' $log
fi

对于 libreoffice,在以下文件中(我从 复制/usr/share/applications/,如 mpv):

$HOME/.local/share/applications/libreoffice-calc.desktop
$HOME/.local/share/applications/libreoffice-draw.desktop
$HOME/.local/share/applications/libreoffice-impress.desktop
$HOME/.local/share/applications/libreoffice-writer.desktop

用。。。来代替Exec

Exec=/home/ismail/.dotfiles/.resources/bash-scripts/libreoffice.sh --calc %U
Exec=/home/ismail/.dotfiles/.resources/bash-scripts/libreoffice.sh --draw %U
Exec=/home/ismail/.dotfiles/.resources/bash-scripts/libreoffice.sh --impress %U
Exec=/home/ismail/.dotfiles/.resources/bash-scripts/libreoffice.sh --writer %U

分别。

libreoffice.sh文件将如下所示:

#!/bin/bash

log=$HOME/.mylibreoffice.log

file=$2

libreoffice "$1" "$2" &
sleep 2

for id in $(xdotool search --onlyvisible --class 'libreoffice')
do
    winpid=$(xdotool getwindowpid $id)
    winname=$(xdotool getwindowname $id)
    grep -q "^$id $winpid .*" $log || echo "$id $winpid $file" >> $log
done

pid_of_libreoffice=$(xdotool search --class 'libreoffice' getwindowpid)

if [ -n "$pid_of_libreoffice" ]
then
    awk -i inplace -v var="$pid_of_libreoffice" '$2 == var {print}' $log
fi

我们的想法是我们不使用很多应用程序。对于我们使用的应用程序,有一些方法可以至少接近我们的预期行为。

笔记:如果脚本的依赖项不存在,请安装它们。特别是你可能需要安装xdotool.

笔记:我用来nemo打开文件,但如果您使用其他文件资源管理器,那么您可能必须相应地更改脚本。只需替换nemonautilus或类似的东西很可能会起作用。

改进领域:

此解决方案不适用于 vscode 等某些应用程序。然而,他们有他们的右键单击 > 打开包含的文件夹选项。

更新1:

我一直在研究一个侏儒扩展让体验变得更好。我在解决这个问题时遇到了一些问题。如果 gnome 善意地公开一项数据(windowID),并更正一项数据(PID),那么这将是一个更好的解决方案。此时此刻,这将是一个黑客。

我在下面的链接中遇到的问题。

https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/6705

https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/6708

https://gitlab.gnome.org/GNOME/glib/-/issues/3016

如果这两个问题得到解决,那么我们希望能够获得一个 gnome 扩展,我们可以使用它“在(几乎)任何应用程序中处理(几乎)任何文件时,使用键盘快捷键,然后在文件系统中打开该文件的父文件夹(当选择该文件时)。”

目前,我不想开发一个 hacky 解决方案,并且我的大部分问题都是通过我上面提到的当前解决方案解决的。

因此,如果这些问题得到解决,请告诉我,希望我能完成工作。

答案2

这将是应用程序的功能,可能通过应用程序使用的 GUI 工具包提供,而不是操作系统或桌面环境的功能。由于您将 Mint 与 Cinnamon 一起使用,因此您可能主要使用 Gnome 应用程序。

在大多数 Gnome 应用程序中,侏儒 ≤3.36(在 Ubuntu 20.04 上测试),以下按键顺序将起作用:Ctrl+O Alt+Up Shift+F10 Return

  1. Ctrl+O是“打开”命令的常用 Gnome 键盘快捷键。它会打开 Gtk 文件打开对话框。接下来的所有内容都适用于使用此文件打开对话框的任何应用程序。该对话框将在包含当前文件的目录中打开。
  2. Alt+Up转到当前目录的父目录。选择上一个目录,即您感兴趣的目录。
  3. Shift+F10调出上下文菜单。
  4. Return选择上下文菜单上的第一个条目,即“使用文件管理器打开”。

如果用鼠标的话,那就是:

  1. 选择“打开文件”命令。 (“另存为”也可以。)
  2. 当前目录的路径显示在顶部,每个目录都在单独的框中。单击右侧第二个框,即当前目录的父目录。
  3. 右键单击所选条目(即您感兴趣的目录)以显示上下文菜单。
  4. 在上下文菜单中选择“使用文件管理器打开”。

我不是 Gnome 专家。也许有更方便的方法。

侏儒≥3.38,不幸的是,这变得更加麻烦,因为文件打开对话框默认显示“最近”列表。要查看包含当前文件的目录,您需要在左侧选项卡中导航到该目录(使用键盘:F6 Down Down...)。然后您可以使用Alt+Up或顶部栏导航到父目录。

凯特(在 19.12.3 上测试),右键单击选项卡标题中的文件名,然后选择“打开所在文件夹”。

相关内容