不时地在多个项目上工作,和/或无论如何,它使我打开了(太多)Vim实例–碰巧,我打开了一个已经在其他地方打开的文件,让我可以选择:

[O]pen Read-only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort


是否有一些内置的方式来引发实例,例如在GUI /终端中,以保存打开的文件?理想情况下,将有问题的文件放到前台(如果有多个缓冲区)。

到目前为止,我正在使用bash脚本,该脚本从swap提取PID,检查该PID是否属于Vim,如果使用,则使用wmctrl升高窗口。尽管这很好用,但至少对于GUI和X11 Linux而言,我在问是否还有一种更本地的方法。

评论

我建议您删除最后一段,并将现有解决方案发布为自我解答。可能会有更好的答案。

我可以拿一份你的剧本吗?

@hildred:不确定您从中得到什么,但最后将其发布了...

注意:Vim带有可编辑的插件

#1 楼

一种解决方案是每个项目使用一个vim实例,除非您的多个项目有重叠的文件,否则这将避免此问题。

我假设您正在寻找一种自动化的解决方案,而不是建议您更改行为。

FocusLost可能有另一种解决方案

FocusLost自动命令事件在GUI Vim和某些控制台终端中起作用。您可以,而不是切换到已打开的vim版本中的文件(如果您使用多个GUI窗口,则该文件是乱七八糟的),则可以保留未在其他vim实例中编写的任何更改都不会丢失(a单独的git分支,保存然后撤消,使其处于撤消树中,或者干脆将其保存),并在新实例中将其打开,并指出之前已将其打开。

另一个潜在有用的自动命令事件是SwapExists,在vim 7中可用,它表示该文件存在交换文件,即IE已打开。 tmux或屏幕,可能有一种方法可以切换到适当的窗口/窗格。

简短的github搜索也会显示https://github.com/lynnard/editexisting.vim,它似乎可以正常工作适用于Xmonad之类的特定窗口管理器。

#2 楼

长期丢失并且几乎被遗忘。

只能重构代码等,但是发布是不变的。此代码在32位系统上使用。不确定在64位(或其他)上的运行方式。

在某处也有C代码的入侵(提取PID)。

将其保留为任何人都可以修改的帖子。我当前的脚本总体而言(使用pid作为选项,鉴于其“ GUI-PID /程序”以及使用wmctrl -l -p等,它应该可以在任何GUI上运行):



#!/bin/bash
# Please leave in place:
# http://vi.stackexchange.com/q/562/220

declare -i debug=1
declare -i pid=0
opt=j

# Usage
usage()
{
    printf "Usage: %s [[opt] <PID>] | [[opt] <SWP>]\n" "${0/*\//}"
    printf "\nopt:\n"
    printf "   j   : Jump to window. (Default)\n"
    printf "   g   : Get window. (E.g. from other workspace.)\n"
    printf "   l   : List windows.\n"
    printf "   p   : Only print. (With some extra info.)\n"
    printf "   s   : Alias for j. (switch)\n"
    printf "   i   : Alias for p. (information)\n"
    printf "   h   : This help.\n"
    printf "\n"
    printf "  <PID>: Process ID.\n"
    printf "  <SWP>: Read PID from Vim swap file.\n"
    if (($#)); then
        printf "\nERR: Unknown option %s\n" ""
    fi
}

# Check if PID is a (G)Vim process
check_vim_pid()
{
    local comm=
    if ! [[ "" =~ ^[0-9]+$ ]];then
        printf "ERR: Some weird thing has happened (P: ).\n" >&2
        exit 1
    fi
    comm="$(ps -p  -o comm=)"
    [[ "$comm" =~ ^g?vim$ ]] && return 0 || return 1
}

# First two bytes should be b0, bc or bC
# Or in hex 0x6230, 0x6263 or 0x6243
check_b0()
{
    local b01="${1:0:2}"
    local b02="${1:2:2}"

    if [[ $b01 != '62' ]] ||
        ([[ "$b02" != '30' && "$b02" != '63' && "$b02" != '43' ]]); then
        return 1
    fi
    return 0
}

# Read PID from swap file.
# Se notes below for information.
vim_file=""
vim_swp_pid()
{
    local swp=""

    if ! [[ -r "$swp" ]]; then
        printf "ERR: Not able to read $swp.\n" >&2
        exit 2
    fi

    # Read b0 ID
    local b0_id="$(xxd -l 2 -p "$swp")"
    if ! check_b0 "$b0_id"; then
        printf "ERR: Bad b0 ID in file (Not Vim-swap?): %s\n" "$b0_id" >&2
        exit 3
    fi
    # Read PID from .swp file
    local -a opid=($(xxd -s 24 -l 4 -p -c 1 "$swp"))
    # Read int magic from .swp file
    local magic=$(xxd -s 1008 -l 8 -p "$swp")

    if [[ "${magic:0:8}" == "33323130" ]]; then
        # Intel (LittleEndian)
        pid=$(printf "%d" "0x${opid[3]}${opid[2]}${opid[1]}${opid[0]}")
    elif [[ "${magic:0:8}" == "30313233" ]] ||
        [[ "${magic:8:8}" == "30313233" ]]; then
        # Motorola (BigEndian)
        pid=$(printf "%d" "0x${opid[0]}${opid[1]}${opid[2]}${opid[3]}")
    else
        printf "ERR: Unknown byteroder: %s\n" "$magic" >&2
        exit 4
    fi
    if ! check_vim_pid $pid; then
        printf "N010: PID %d is not a Vim process.\n" "$pid" >&2
        exit 10
    fi
    # Read file name
    vim_file="$(xxd -s 108 -l 800 -ps "" | xxd -r -p)"
}

list_windows()
{
    local winid desk pid host title comm
    printf "%-10s %-3s %-6s %-16s %s\n" "WINID" "DSK" "PID" "COMM" "TITLE"
    while IFS=$' \n' read -r winid desk pid host title; do
        cf="/proc/$pid/comm"
        [[ -r "$cf" ]] && read -r comm < "$cf"
        printf "%10s %3d %6d %-16s %s\n" "$winid" "$desk" "$pid" "$comm" "$title"
    done <<< "$(wmctrl -lp)"
}
# ------------------------- RUN -------------------------------------------- #

# Check if any arguments (a bit redundant, but OK)
if [[ -z "" ]]; then
    usage >&2
    exit 1
fi

# Loop arguments
while [[ "" ]]; do
    if [[ "" =~ ^[0-9]+$ ]]; then
        pid=
    else
        [[ "${1:0:1}" == "-" ]] && op=${1:1} || op=
        case "$op" in
        l) list_windows; exit 0;;
        d) debug=1;;
        h|-help) usage; exit 0;;
        j|s|g|p|i) opt=$op;;
        *)
            if ! [[ -e "" ]]; then
                usage >&2;
                printf "\nE006: Can't stat \`%s'\n" "" >&2
                exit 2
            fi
            vim_swp_pid ""
            ;;
        esac
    fi
    shift
done

# Check if PID is set
if !(($pid)); then
    usage >&2
    printf "E011: PID required / Not found.\n" >&2
    exit 11
fi

# Read WindowID, Workspace, PID of all-windows then filter by PID
read -r wid ws <<<$(wmctrl -l -p | awk -v p="$pid" ' == p {print ,"\t",}')

pikoli()
{
    local pp=
    while :; do
        awk '/^PPid:/{print ;next}/^Name:/{print ;next}' /proc/$pp/status 2>/dev/null || return
        pp=$(awk '/^PPid:/{print ;next}' /proc/$pp/status)
    done
}

if ! [[ "$wid" ]]; then
    pikoli $pid
    printf "ERR: Window not fround from PID %d.\n" "$pid" >&2
    exit 12
fi

# As most DM's names desktops from 1 and not 0, a more user-friendly number.
((dmws=ws + 1))

# Do the action!
((debug)) && printf "PID=%d, WID=%s, WS=%d\n" "$pid" "$wid" "$ws"
case "$opt" in
j|s)    printf "Swithching to workspace %d raising window %s by PID %d.\n" \
        "$dmws" "$wid" "$pid";
    wmctrl -ia "$wid"
    ;;
g)    printf "Getting window %s by PID %d from workspace %d.\n" \
        "$wid" "$pid" "$dmws";
    wmctrl -iR "$wid"
    ;;
i|p)    printf "Window is on workspace %d having window ID %s by PID %d.\n" \
        "$dmws" "$wid" "$pid";
    xwininfo -id $wid
    ;;
esac

exit 0

#############################################################################
# ----------------- Vim swap file block zero format ----------------------- #
#############################################################################
#
# No script / bash code beyond here
#

NOTES 'memline.c:139':

:62
#define BLOCK0_ID0     'b'          /* block 0 id 0 */
#define BLOCK0_ID1     '0'          /* block 0 id 1 */
#define BLOCK0_ID1_C0  'c'          /* block 0 id 1 'cm' 0 */
#define BLOCK0_ID1_C1  'C'          /* block 0 id 1 'cm' 1 */

:124
#define B0_FNAME_SIZE_ORG   900 /* what it was in older versions */
#define B0_FNAME_SIZE_NOCRYPT   898 /* 2 bytes used for other things */
#define B0_FNAME_SIZE_CRYPT 890 /* 10 bytes used for other things */
#define B0_UNAME_SIZE       40
#define B0_HNAME_SIZE       40
/*
 * Restrict the numbers to 32 bits, otherwise most compilers will complain.
 * This won\'t detect a 64 bit machine that only swaps a byte in the top 32
 * bits, but that is crazy anyway.
 */
#define B0_MAGIC_LONG   0x30313233L
#define B0_MAGIC_INT    0x20212223L
#define B0_MAGIC_SHORT  0x10111213L
#define B0_MAGIC_CHAR   0x55

:139
/*
 * Block zero holds all info about the swap file.
 *
 * NOTE: DEFINITION OF BLOCK 0 SHOULD NOT CHANGE! It would make all existing
 * swap files unusable!
 *
 * If size of block0 changes anyway, adjust MIN_SWAP_PAGE_SIZE in vim.h!!
 *
 * This block is built up of single bytes, to make it portable across
 * different machines. b0_magic_* is used to check the byte order and size of
 * variables, because the rest of the swap file is not portable.
 */
struct block0
{
    char_u  b0_id[2];   /* id for block 0: BLOCK0_ID0 and BLOCK0_ID1,
                 * BLOCK0_ID1_C0, BLOCK0_ID1_C1 */
    char_u  b0_version[10]; /* Vim version string */
    char_u  b0_page_size[4];/* number of bytes per page */
    char_u  b0_mtime[4];    /* last modification time of file */
    char_u  b0_ino[4];  /* inode of b0_fname */
    char_u  b0_pid[4];  /* process id of creator (or 0) */
    char_u  b0_uname[B0_UNAME_SIZE]; /* name of user (uid if no name) */
    char_u  b0_hname[B0_HNAME_SIZE]; /* host name (if it has a name) */
    char_u  b0_fname[B0_FNAME_SIZE_ORG]; /* name of file being edited */
    long    b0_magic_long;  /* check for byte order of long */
    int     b0_magic_int;   /* check for byte order of int */
    short   b0_magic_short; /* check for byte order of short */
    char_u  b0_magic_char;  /* check for last char */
};

offs    len     what
0       2       id
2       10      version
12      4       bytes per page
16      4       mtime
20      4       inode
24      4       PID or 0
28      40      name of user or uid
68      40      host name
108     900     fname
1008    4/8/    magic long*
1012    4/8/    magic int*
1016    2/      magic short*
1018    1/      magic char*

Length of magics is arch dependant.
Offset for magic, in example above, is by standard 32 bit.