Zachowaj zmodyfikowany znacznik czasu po edycji

20

W przypadku plików w określonym folderze chciałbym, aby vim nigdy nie dotykał „zmodyfikowanego” znacznika czasu.

Tłem jest to, że używam Bloxsom do blogowania, który używa zwykłych plików tekstowych ~/bloxsomjako źródła wszystkich artykułów. Data artykułu (a zatem kolejność wyświetlania) oparta jest na dacie modyfikacji pliku tekstowego. Nie chcę, aby artykuł pojawiał się, jakby był nowy, gdy tylko naprawię literówkę. (Robię ich dużo ...: D)

Do tej pory vim zmienia znacznik czasu, a oryginalny znaczek ginie na zawsze. To jest OK i chcę to zachować dla większości plików w systemie. Ale nie chcę tego dla plików bloga - zawsze mogę touchplik, jeśli zajdzie taka potrzeba.

Masz jakieś pomysły, jak dostosować Vima do tego zachowania?

Alois Mahdal
źródło
2
vim.wikia.com/wiki/… - zamiast tego możesz oczywiście używać powiązań perla
Ulrich Dangel

Odpowiedzi:

22

Nie sądzę, że vim ma tę funkcję. Jedną z możliwości jest odpowiednia modyfikacja kopii i odpowiednie ustawienie znacznika czasu, np .:

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

Lub nawet lepiej:

touch -r post timestamp
vim post
touch -r timestamp post
Thor
źródło
7

Jeśli chcesz się zabawić:

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

Zamień ścieżkę na rzeczywistą ścieżkę pliku

Shâu Shắc
źródło
5

Napisałem do tego skrypt Perla.

Jest to opakowanie wokół vima, zapisane ~/bin/vim-nomtime.pli wprowadzone do użycia alias vim='~/bin/vim-nomtime.pl'w moim .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->{$_}, $_;
    }
}

Niektóre dobre funkcje:

  • obsługuje wiele nazw plików

  • obsługuje wiele „oglądanych” katalogów

  • obsługuje dowiązanie symboliczne reż

  • można rozszerzyć o inne kryteria

z których większość można prawdopodobnie osiągnąć również w wersji czystego vima. Wady tego rozwiązania w porównaniu z moim pożądanym rozwiązaniem pure-vim to:

  • przywraca znaczek dopiero po zakończeniu vima, więc jeśli wykonam długą edycję i regularnie zapisuję, plik villi wyskakuje jako nowy, dopóki nie wyjdę z vima

  • obsługuje wiele plików w wierszu poleceń, ale w dość naiwny sposób - sprawdza tylko, czy @ARGVplik jest plikiem. Prawdopodobnie nie działałoby to z symbolami wieloznacznymi (np. vim note-*.txt) Ani innymi zabawnymi rzeczami

  • nie jest odporny na awarie, prawdopodobnie nawet nie jest odporny na HUP (można to zrobić)

  • ... wel, to jest opakowanie. (Chodzi mi o to, że gdybyśmy rozwiązali wszystko za pomocą opakowania, ile mielibyśmy opakowań, zanim wydarzyło się coś złego?)

Alois Mahdal
źródło
3 maja 2019 r. I właśnie zmodyfikowałem plik z 11 listopada 2017 r. Zawiera on zarówno moją modyfikację, jak i zachowuje oryginalny znacznik czasu. :)
jmort253
1

Ten krótki skrypt zachowa zmodyfikowany czas, jeśli katalog macierzysty pliku zawiera .nomtimeplik:

#!/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
Xiè Jìléi
źródło
1

Wypróbuj tę bashfunkcję (w oparciu o odpowiedź Shâu Shắc )

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

Teraz możemy edytować plik i zachować zmodyfikowany czas za pomocą tego

vi-preserve-time file1.txt file2.txt
Steely Wing
źródło
(1) Jest to prawie identyczne z odpowiedzią Shâu Shắca sprzed pięciu lat. (2) Zakłada się, że użytkownik wywołuje vitylko jeden plik naraz; to nie zadziała vi file1 file2. (3) Oczywiste jest, że jeśli użytkownik przełączy się na inny plik za pomocą :e, nie będzie to obsługiwane.
G-Man mówi „Przywróć Monikę”
Przepraszam, że zapomniałem odwoływać się, teraz dodałem link referencyjny do odpowiedzi Shâu Shắc.
Steely Wing,
Jeśli chodzi o twoje pytanie nr 3, myślę, że jeśli otworzysz inny plik, którego nie ma w wierszu poleceń, to twój problem.
Steely Wing,
1
Chodzi mi o to, że jeśli pytanie brzmi „Jak sprawić, aby vim zachowywał się tak, jak chcę?”, A Ty udostępniasz funkcję, która wygląda tak, jakby zachowywała się tak, jak chce użytkownik, Twoim obowiązkiem jest udokumentowanie wszelkich ograniczeń twojego odpowiedź. OK, może mój komentarz jest trochę niesprawiedliwy, ponieważ wszystkie inne odpowiedzi wydają się mieć takie same ograniczenia i żadna z nich nie wspomina o tym, o ile wiem. Właśnie sprawdzałem twoją odpowiedź, ponieważ była nowa; Nie spędziłem dużo czasu, patrząc na inne odpowiedzi.
G-Man mówi „Przywróć Monikę”
1

Istnieje możliwość skopiowania znacznika czasu z innego pliku.

touch -m -r file_source file_target

Przykład:

[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
użytkownik352752
źródło
1

Znalazłem świetne rozwiązanie na tej stronie , która tworzy funkcję vim, aby zapisać bieżący plik przy jednoczesnym zachowaniu istniejącego czasu modyfikacji, i wiąże tę funkcję z F4klawiszem funkcyjnym:

Odkryłem jednak, że oryginalna funkcja zawiera niewielki błąd, który powoduje wyświetlenie następującego ostrzeżenia, jeśli F4zostanie użyty dwukrotnie w tym samym pliku, ponieważ vim jest zdezorientowany, gdy zmienia się czas modyfikacji:

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

Na szczęście łatwo to naprawić: dodałem polecenie „edytuj” do oryginalnej funkcji, aby ponownie załadować plik po przywróceniu znacznika czasu, więc vim wie, jaki czas modyfikacji będzie oczekiwać na plik.

Oto zmodyfikowana funkcja vim z tą poprawką błędu, którą można dodać do ~/.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>

Uwaga: Funkcja ta opiera się na wersji GNU date, stata touch.

Deven T. Corzine
źródło
0

Korzystając z niektórych opisanych powyżej pojęć, oto bardzo szybki i brudny alias jednowierszowy dla CSH, który udostępnia do tego celu polecenie „edycji”:

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

Możesz łatwo użyć zmiennej środowiskowej $ VISUAL lub $ EDITOR zamiast „vim”. W ten sposób możesz wydać następujące polecenie, aby zmienić domyślne edytory

setenv VISUAL nano

Teraz sam alias nie musi być przedefiniowywany w celu dostosowania go do różnych edytorów, co czyni go nieco bardziej przenośnym. Jeśli używasz powłoki innej niż CSH lub TCSH, oczywiście powyższe przykłady można odpowiednio dostosować.

Leslie Krause
źródło