Created
January 31, 2012 22:20
-
-
Save xolox/1713414 to your computer and use it in GitHub Desktop.
Lua script to restore ZSH history file from backups (useful for completion)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env lua | |
-- Posted this online because of http://news.ycombinator.com/item?id=3535349 | |
ordered = {} | |
index = {} | |
need_continuation = false | |
first_continued_line = 0 | |
function add_or_replace(line) | |
-- ZSH uses special markers when appending to the command history file which | |
-- enables it to share the command history between concurrent ZSH sessions. | |
-- When joining several history files however the markers should be removed: | |
if line:find '^:%s%d+:%d;%s?.+' then | |
-- Convert e.g. ": 1257020658:0;ls" to "ls". | |
line = line:match '^:%s%d+:%d;%s?(.+)' | |
end | |
-- Add the line to the ordered list of commands. | |
table.insert(ordered, line) | |
-- Detect the range of multi-line commands. | |
local backcont = need_continuation -- previous line indicated continuation. | |
local forwcond = line:find '\\$' -- current line indicates continuation. | |
need_continuation = forwcond | |
local first_line = #ordered | |
local last_line = first_line | |
local index_key = line:gsub('^%s*(.-)%s*$', '%1') | |
if forwcond and not backcont then | |
-- First line of multi-line command. | |
first_continued_line = first_line | |
-- Don't add this line to the index. | |
index_key = nil | |
elseif backcont and not forwcond then | |
-- Last line of multi-line command. | |
first_line = first_continued_line | |
-- Create index key from concatenated lines. | |
index_key = {} | |
for i = first_line, last_line do | |
table.insert(index_key, ordered[i]) | |
end | |
index_key = table.concat(index_key, '\n') | |
elseif backcont or forwcond then | |
-- Don't add this line to the index. | |
index_key = nil | |
end | |
if index_key then | |
if index[index_key] then | |
-- Hide previous occurrence of command. | |
local r = index[index_key] | |
for i = r[1], r[2] do ordered[i] = '' end | |
end | |
index[index_key] = {first_line, last_line} | |
end | |
end | |
-- Collect the command history of the last year or so from my backups: | |
pipe = io.popen("ssh my-backup-server 'cat $HOME/Backups/Laptop/*/home/peter/.z_history'", 'r') | |
for line in pipe:lines() do add_or_replace(line) end | |
pipe:close() | |
-- Now merge it with the command history on my laptop: | |
file = io.open('/home/peter/.z_history', 'r') | |
for line in file:lines() do add_or_replace(line) end | |
file:close() | |
-- Print the results. | |
for i = 1, #ordered do | |
local line = ordered[i] | |
if line ~= '' then | |
io.write(line, '\n') | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment