Поднять окно с файлом подкачки

13

Время от времени, работая над несколькими проектами и / или чем-либо другим, у меня остается (слишком) много экземпляров Vim - как это бывает, я открываю файл, который уже открыт в другом месте, оставляя мне возможность:

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

Есть ли какой-нибудь встроенный способ поднять экземпляр, как в GUI / терминал, содержащий открытый файл? Идеально выводит файл на передний план (если несколько буферов).

На данный момент я использую сценарий bash, который извлекает PID из свопа, проверяет, принадлежит ли этот PID к Vim, и если да, то использует его wmctrlдля вызова окна. Хотя это работает нормально, по крайней мере, для GUI и в Linux X11, я спрашиваю, есть ли более родной способ.

Runium
источник
4
Я предлагаю вам удалить последний абзац и опубликовать существующее решение в качестве самостоятельного ответа. Кто-то может прийти с лучшим ответом.
200_success
1
могу ли я получить копию вашего сценария?
Hildred
@hildred: Не уверен, что вы что-то получаете от него, но наконец-то опубликовал ...
Runium

Ответы:

4

Одним из решений будет использование одного экземпляра vim для каждого проекта, что предотвратит эту проблему, если в ваших проектах не будут перекрывающиеся файлы.

Я собираюсь предположить, что вы ищете автоматизированное решение, а не предложение по изменению вашего поведения.

Существует возможность другого решения в FocusLost , более родного для vim.

Событие автокоманды FocusLost работает в графическом интерфейсе Vim и в некоторых консольных терминалах. Вы можете вместо переключения на файл в версии vim, которая открыта (которая, если вы используете несколько окон с графическим интерфейсом, является грязной), сохранить любые изменения, которые не были записаны в другом экземпляре vim, не будут потеряны (a отделите ветку git, сохраните, затем отмените, чтобы она была в дереве отмен, или просто сохраните ее) и откройте ее в новом экземпляре с указанием того, что он был открыт ранее.

Другое потенциально полезное событие автокоманды , доступное в vim 7, - это SwapExists , который указывает, что для файла существует файл подкачки, т.е. он открыт.

Если вы сохранили все в tmux или screen, возможно, есть способ переключиться на соответствующее окно / панель.

Краткий поиск в github также вызывает https://github.com/lynnard/editexisting.vim, который работает для определенных оконных менеджеров, таких как Xmonad.

user50136
источник
3

Давно потеряно и почти забыто.

Имеется в виду, чтобы повторно фактор кода и т. Д., Но пост, как есть. Этот код используется в 32-битной системе. Не уверен, как он будет себя вести на 64-битной (или другой).

Также есть где-нибудь взломать C-код (извлечение PID).

Оставьте это как сообщение для любого, чтобы взломать и настроить. Мой текущий скрипт в целом (используя его pidкак опцию, он должен работать на любом графическом интерфейсе, учитывая его «GUI-PID / Program» и использование wmctrl -l -pи так далее):

#!/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" "$1"
    fi
}

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

    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 "$1" | 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 "$1" ]]; then
    usage >&2
    exit 1
fi

# Loop arguments
while [[ "$1" ]]; do
    if [[ "$1" =~ ^[0-9]+$ ]]; then
        pid=$1
    else
        [[ "${1:0:1}" == "-" ]] && op=${1:1} || op=$1
        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 "$1" ]]; then
                usage >&2;
                printf "\nE006: Can't stat \`%s'\n" "$1" >&2
                exit 2
            fi
            vim_swp_pid "$1"
            ;;
        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" '$3 == p {print $1,"\t",$2}')

pikoli()
{
    local pp=$1
    while :; do
        awk '/^PPid:/{print $2;next}/^Name:/{print $2;next}' /proc/$pp/status 2>/dev/null || return
        pp=$(awk '/^PPid:/{print $2;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.
Runium
источник