Зберегти змінену позначку часу після редагування


20

Для файлів у певній папці я б хотів, щоб vim взагалі ніколи не торкався "модифікованих" часових позначок.

Фон полягає в тому, що я використовую Bloxsom для ведення блогів, який використовує текстові файли звичайного тексту ~/bloxsomяк джерело всіх статей. Дата статті (і, отже, порядок появи) заснована на даті зміни текстового файлу. Я не хочу, щоб статті вискакували, як якщо вона нова, коли я просто виправляю друк. (Я їх дуже багато ...: D)

Поки що vim змінює часову позначку, і початковий штамп втрачається назавжди. Це нормально, і я хочу зберегти це таким чином для більшості файлів у системі. Але я не хочу цього для файлів блогу - я завжди можу touchфайл, якщо мені це потрібно.

Будь-які ідеї про те, як налаштувати vim у цій поведінці?


2
vim.wikia.com/wiki/… - ви, звичайно, можете використовувати заміни perl замість цього
Ульріх Дангел

Відповіді:


22

Я не думаю, що vim має таку особливість. Однією з альтернатив є зміна копії та встановлення часової позначки відповідно, наприклад:

cp -p post temp
vim temp
touch -r post temp
cp -p temp post

Або ще краще:

touch -r post timestamp
vim post
touch -r timestamp post

7

Якщо вам потрібно повеселитися:

file=path; mtime=$(stat -c %y "$file"); vi "$file"; touch -d "$mtime" "$file"

Замініть шлях на власний шлях до файлу


5

Я написав для цього сценарій Perl.

Це обгортка навколо vim, збережена ~/bin/vim-nomtime.plта введена в експлуатацію через alias vim='~/bin/vim-nomtime.pl'мій .bashrc.

#!/usr/bin/perl
use strict;
use warnings;
use Cwd qw/ abs_path /;

my @dirs = qw( ~/blosxom /srv/relief/blosxom );

s/^~/$ENV{HOME}/ foreach @dirs;

# do we want to preserve stamp on this file?
sub fits {
    my $dir = abs_path($_[0]);
    my $fits = 0;
    foreach (@dirs) {
        my $preserved_dir = abs_path($_);
        $fits++ if $dir =~ m|^$preserved_dir|;
    }
    return $fits != 0;
}

# store original stamps
my $original_stamp;
foreach (@ARGV) {
    if ( -f $_ and fits($_) ) {
        $original_stamp->{$_} = (stat($_))[9];
    }
}

# run vim as you would
my $cmd = join ' ', 'vim', @ARGV;  
system($cmd) == 0
    or die "vim failed: $!";

# restore stamps if they have changed
foreach (keys %$original_stamp) {
    next unless -f $_;
    my $current_stamp = (stat($_))[9];
    unless ($current_stamp == $original_stamp->{$_}) {
        utime $original_stamp->{$_}, $original_stamp->{$_}, $_;
    }
}

Деякі хороші особливості:

  • підтримує кілька імен файлів

  • підтримує численні "переглянуті" dir

  • підтримує символічно пов'язаний реж

  • може бути покращено за допомогою інших критеріїв

більшість з яких можна було б досягти і з чистою версією vim. Недоліками цього рішення в порівнянні з бажаним рішенням чистого виду є:

  • він відновлює марку лише після того, як vim вийшов, тому якщо я довго редагую та зберігаю регулярно, файл vill "спливаюче" як новий, поки я не вийду з vim

  • він підтримує декілька файлів у командному рядку, але досить наївним способом - він перевіряє лише, чи є річ @ARGVу файлі. Це, мабуть, не спрацює із символами підказки (наприклад vim note-*.txt) чи іншими смішними матеріалами

  • це не стійкість до аварійних дій, мабуть навіть не HUP-стійкий (що можна зробити)

  • ... ну, це обгортка. (Я маю на увазі, якби ми все вирішили за допомогою обгортки, скільки обгортки було б у нас, перш ніж трапилось щось погане?)


3 травня 2019 року, і я щойно змінив файл з 11 листопада 2017 року, і він має і мою модифікацію, і зберігає початкову мітку часу. :)
jmort253

1

Цей короткий сценарій збереже модифікований час, якщо будь-який батьківський dir файлу містить .nomtimeфайл:

#!/bin/bash

dir="${1%/*}"
[ "$dir" = "$1" ] && dir=.
dir=$( readlink -f "$dir" )

nomtime=
while [ -n "$dir" ]; do
    if [ -f "$dir/.nomtime" ]; then
        nomtime=1
        break
    fi
    dir="${dir%/*}"
done

if [ "$nomtime" = 1 ]; then
    T=`tempfile`
    touch -r "$1" $T
fi

vi "$1"

if [ "$nomtime" = 1 ]; then
    touch -r $T "$1"
    rm $T
fi

1

Спробуйте цю bashфункцію ( базуйтесь на відповіді Шяу Шока )

vi-preserve-time () {
    for file in "$@"; do
        local mtime=$(stat -c %y "$file")
        vi "$file"
        touch -d "$mtime" "$file"
    done
}

Тепер ми можемо редагувати файл і зберігати модифікований час за допомогою цього

vi-preserve-time file1.txt file2.txt

(1) Це майже ідентично відповіді Шяу Шоца від п'яти років тому. (2) Це передбачає, що користувач viодночасно запускає лише один файл; це не буде працювати vi file1 file2. (3) Само собою зрозуміло, що якщо користувач перейде на інший файл :e, він не буде оброблятися.
G-Man каже: "Відновіть Моніку"

Вибачте про забувши посилання, тепер я додав посилання на відповідь на відповідь Шяу Шока.
Стілі Вінг

Щодо вашого питання №3, я думаю, якщо ви відкриєте інший файл не в командному рядку, це ваша проблема.
Стілі Вінг

1
Моя думка, якщо у запитанні "Як я можу змусити vim вести себе так, як мені хочеться?" відповідь. Гаразд, можливо, мій коментар є трохи несправедливим, оскільки всі інші відповіді, мабуть, мають однакове обмеження, і жодна з них не згадує, наскільки я можу сказати. Я щойно переглядав вашу відповідь, тому що вона була нова; Я не витрачав багато часу на перегляд інших відповідей.
G-Man каже: "Відновіть Моніку"

1

Є можливість скопіювати часову позначку з іншого файлу.

touch -m -r file_source file_target

Приклад:

[oracle@es abc]$ ls -tlr
total 4
-rw-r--r--. 1 oracle oinstall 102 May  8 20:35 aa.txt
[oracle@es abc]$ echo "hi hi" > b
[oracle@es abc]$ ls -ltr
total 4
-rw-r--r--. 1 oracle oinstall 102 May  8 20:35 aa.txt
-rw-r--r--. 1 oracle oinstall   6 May 13 18:58 b
[oracle@es abc]$ touch -m -r aa.txt b
[oracle@es abc]$ ls -tlr
total 8
-rw-r--r--. 1 oracle oinstall   6 May  8 20:35 b
-rw-r--r--. 1 oracle oinstall 102 May  8 20:35 aa.txt
[oracle@es abc]$ cat b
hi hi

1

На цій веб-сторінці я знайшов чудове рішення , яке створює функцію vim для збереження поточного файлу при збереженні існуючого часу модифікації та прив’язує цю функцію до F4функціональної клавіші:

Однак я виявив, що оригінальна функція містить незначну помилку, що викликає таке попередження, якщо F4вона використовується два рази в одному файлі, оскільки vim плутається, коли змінюється час модифікації:

WARNING: The file has been changed since reading it!!!
Do you really want to write to it (y/n)?

На щастя, це легко виправити: я додав команду «редагування» до оригінальної функції, щоб перезавантажити файл після відновлення часової позначки, тому vim знає, який час модифікації очікувати у файлі.

Ось змінена функція vim із цим виправленням помилок, яку можна додати до ~/.vimrc:

function! WriteSmall()
    let mtime = system("date -d @`stat -c %Y ".shellescape(expand('%:p')) . "`")
    write
    call system("touch --date='".mtime."' ".shellescape(expand('%:p')))
    edit
endfunction
map <F4> :call WriteSmall()<CR>

Примітка: Ця функція залежить від GNU версії date, statі touch.


0

Використовуючи деякі з описаних вище понять, ось дуже швидкий і брудний однолінійний псевдонім для CSH, який робить команду "редагування" доступною для цієї мети:

alias edit 'touch -r \!:1 /tmp/~mtime ; vim \!:1 ; touch -r /tmp/~mtime \!:1 ; rm /tmp/~mtime'

Ви можете легко використовувати змінну середовища $ VISUAL або $ EDITOR замість "vim". Таким чином ви можете видати наступну команду для зміни редакторів за замовчуванням

setenv VISUAL nano

Тепер сам псевдонім не потрібно переробляти для розміщення різних редакторів, роблячи його дещо більш портативним. Якщо ви використовуєте оболонку, відмінну від CSH або TCSH, звичайно, наведені вище приклади можна відповідно адаптувати.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.