├── README.md ├── changelog.md ├── example.gif ├── license.txt ├── lua └── eswpoch │ ├── init.lua │ ├── timezones.lua │ ├── ui.lua │ └── util.lua └── plugin └── eswpoch.vim /README.md: -------------------------------------------------------------------------------- 1 | # Eswpoch - Nvim 2 | 3 | Toggles a menu which allows swapping between units and human readable strings of a configurable set of timezones 4 | for a given timestamp. Port of the original VSCode plugin: https://github.com/hlucco/eswpoch. 5 | 6 | ## Example 7 | 8 | ![example gif](https://raw.githubusercontent.com/hlucco/nvim-eswpoch/master/example.gif) 9 | 10 | ## Installation 11 | 12 | Using a plugin manager: 13 | 14 | `Plug 'hlucco/nvim-eswpoch'` 15 | 16 | ## Commands 17 | 18 | `:Eswpoch` -> Brings up the epoch swap menu. 19 | 20 | ## Overview 21 | 22 | Once the cursor is over a valid timestamp value, using the `:Eswpoch` command the menu will open 23 | and display the detected timestamp value in the user input bar. The options will be the supported conversations for that timestamp. Exit the menu and 24 | change nothing or cycle through the options and select one to cycle out. The old value will be replaced with the new value converted in line. 25 | 26 | In addition to unit conversions, the menu will also show a converted human readable string for all of the IANA time zones that have been added to the 27 | `timezones` variable in `lua/eswpoch.lua`. Selecting one of these strings will swap the original value for the selected human readable string. 28 | 29 | ## Configuration 30 | 31 | To add or remove time zone options from the menu, edit the `timezones` table in `lua/eswpoch.lua` to add 32 | or remove timezone entries. Each timezone entry must be accompanied by it's GMT offset value. For example, 33 | `-7` for `America/Los_Angeles`. 34 | 35 | ```lua 36 | timezones = { 37 | America_Los_Angeles = -7, 38 | America_Chicago = -5, 39 | America_New_York = -4 40 | } 41 | ``` 42 | 43 | To change the command which activates the menu, update the `plugin/eswpoch.vim` command entry 44 | with a desired command string for activation. 45 | 46 | ```lua 47 | command! lua require'eswpoch'.eswpoch() 48 | ``` 49 | 50 | Version 1.0.1 51 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | ## 1.0.2 2 | 3 | - Fixed bug with popup buf size being weird when terminal pane is small. 4 | - Fixed bug where it was not possible to select more then the first three timezoneks. 5 | - Updated plugin structure to be easier to read and understand then one large file. 6 | 7 | ## 1.0.1 8 | 9 | - Fix bug with human readable date always showing current time 10 | - Fixed error when moving past the end of the window (k keypress) 11 | 12 | ## 1.0.0 13 | 14 | - Initial release 15 | -------------------------------------------------------------------------------- /example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlucco/nvim-eswpoch/d2ce6d26524cb3cbcfb9a48b4c7e1bae10c2440b/example.gif -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Henry Lucco 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 12 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 13 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 14 | IN THE SOFTWARE. 15 | -------------------------------------------------------------------------------- /lua/eswpoch/init.lua: -------------------------------------------------------------------------------- 1 | local util = require("eswpoch.util") 2 | local ui = require("eswpoch.ui") 3 | local timezones = require("eswpoch.timezones") 4 | 5 | local api = vim.api 6 | local c_row, c_col 7 | local line 8 | local parent_buf 9 | 10 | local function get_token() 11 | local char_idx = 1 12 | local token_idx = 1 13 | local result = "" 14 | local trim_line = util.trim(line) 15 | for token in string.gmatch(trim_line, "%S+") do 16 | local trim_token = util.trim(token) 17 | char_idx = char_idx + string.len(trim_token) 18 | if char_idx + token_idx + 1>= c_col then 19 | result = token 20 | break 21 | end 22 | token_idx = token_idx + 1 23 | end 24 | return result 25 | end 26 | 27 | local function render_options(token, buf) 28 | api.nvim_buf_set_option(buf, 'modifiable', true) 29 | local digits = string.len(token) 30 | local unit = 's'; 31 | 32 | if digits >= 12 then 33 | unit = 'ms' 34 | end 35 | 36 | if digits >= 15 then 37 | unit = 'us' 38 | end 39 | 40 | if digits >= 17 then 41 | unit = 'ns' 42 | end 43 | 44 | local conversions = { 45 | s = { 46 | s = 1, 47 | ms = 1000, 48 | us = 1e6, 49 | ns = 1e9 50 | }, 51 | ms = { 52 | s = 1/1000, 53 | ms = 1, 54 | us = 1000, 55 | ns = 1e6 56 | }, 57 | us = { 58 | s = 1/1e6, 59 | ms = 1/1000, 60 | us = 1, 61 | ns = 1000 62 | }, 63 | ns = { 64 | s = 1/1e9, 65 | ms = 1/1e6, 66 | us = 1/1000, 67 | ns = 1 68 | } 69 | } 70 | 71 | local conversion_results = {} 72 | local initial_value = tonumber(token) 73 | local conversion_table = conversions[unit] 74 | for unit, mult in pairs(conversion_table) do 75 | local c = initial_value * mult 76 | conversion_results[unit] = c 77 | end 78 | 79 | local i = 1 80 | local unit_s = 0 81 | 82 | for unit, c in pairs(conversion_results) do 83 | if unit == 's' then 84 | unit_s = c 85 | end 86 | local formatted_entry = string.format("%.f", c) 87 | local line_entry = unit..": "..formatted_entry 88 | api.nvim_buf_set_lines(buf, i, i + 1, false, {line_entry}) 89 | i = i + 1 90 | end 91 | 92 | api.nvim_buf_set_lines(buf, i, i+1, false, {ui.gen_divider()}) 93 | i = i + 1 94 | 95 | for k,v in pairs(timezones) do 96 | local date_string = os.date("!%a %b %d, %I:%M %p, %Y", unit_s + (v * 60 * 60)) 97 | local line_entry = k..": "..date_string 98 | api.nvim_buf_set_lines(buf, i, i+1, false, {line_entry}) 99 | i = i + 1 100 | end 101 | 102 | api.nvim_buf_set_option(buf, 'modifiable', false) 103 | 104 | end 105 | 106 | local function insert_selection() 107 | local token = get_token() 108 | local anchor = string.find(line, token) 109 | local active = anchor + string.len(token) 110 | 111 | local insert_value = util.trim(util.split(api.nvim_get_current_line(), "([^:]+)")[2]) 112 | local split_point = string.find(api.nvim_get_current_line(), ":") 113 | local insert_tokens = util.split(api.nvim_get_current_line(), "([^:]+)") 114 | 115 | local count = 1 116 | for k, v in pairs(insert_tokens) do 117 | count = count + 1 118 | end 119 | 120 | if (count > 3) then 121 | insert_value = '"'..util.trim(string.sub(api.nvim_get_current_line(), split_point+1))..'"' 122 | end 123 | 124 | local new_line = string.sub(line, 1, anchor-1)..insert_value..string.sub(line, active, string.len(line)) 125 | local ts = 1658669410000000000 126 | api.nvim_buf_set_lines(parent_buf, c_row-1, c_row, false, {new_line}) 127 | ui.close_window() 128 | end 129 | 130 | local function set_mappings(buf) 131 | local mappings = { 132 | q = 'close_window()', 133 | k = 'move_cursor(false)', 134 | j = 'move_cursor(true)', 135 | [''] = 'insert_selection()' 136 | } 137 | 138 | for k, v in pairs(mappings) do 139 | api.nvim_buf_set_keymap(buf, 'n', k, ':lua require"eswpoch".'..v..'',{ 140 | nowait = true, noremap = true, silent = true 141 | }) 142 | end 143 | 144 | local other_chars = { 145 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'i', 'n', 'o', 'p', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ':', 'h', 'l' 146 | } 147 | 148 | for k,v in ipairs(other_chars) do 149 | api.nvim_buf_set_keymap(buf, 'n', v, '', { nowait = true, noremap = true, silent = true }) 150 | api.nvim_buf_set_keymap(buf, 'n', v:upper(), '', { nowait = true, noremap = true, silent = true }) 151 | api.nvim_buf_set_keymap(buf, 'n', '', '', { nowait = true, noremap = true, silent = true }) 152 | end 153 | end 154 | 155 | local function eswpoch() 156 | parent_buf = api.nvim_win_get_buf(0) 157 | c_row, c_col = unpack(api.nvim_win_get_cursor(0)) 158 | line = api.nvim_buf_get_lines(0, c_row-1, c_row, false)[1] 159 | local token = get_token() 160 | local buf = ui.open_window() 161 | render_options(token, buf) 162 | set_mappings(buf) 163 | end 164 | 165 | return { 166 | eswpoch = eswpoch, 167 | close_window = ui.close_window, 168 | move_cursor = ui.move_cursor, 169 | insert_selection = insert_selection 170 | } 171 | -------------------------------------------------------------------------------- /lua/eswpoch/timezones.lua: -------------------------------------------------------------------------------- 1 | local timezones = { 2 | America_Los_Angeles = -7, 3 | America_Chicago = -5, 4 | America_New_York = -4, 5 | } 6 | 7 | return timezones 8 | -------------------------------------------------------------------------------- /lua/eswpoch/ui.lua: -------------------------------------------------------------------------------- 1 | local util = require("eswpoch.util") 2 | local timezones = require("eswpoch.timezones") 3 | local api = vim.api 4 | local buf, win_height, win_width, win 5 | 6 | local function open_window() 7 | buf = api.nvim_create_buf(false, true) 8 | local border_buf = api.nvim_create_buf(false, true) 9 | api.nvim_buf_set_option(buf, 'bufhidden', 'wipe') 10 | 11 | local width = api.nvim_get_option("columns") 12 | local height = api.nvim_get_option("lines") 13 | 14 | win_height = math.ceil(height * 0.2 - 5) 15 | win_width = math.ceil(width * 0.3) 16 | 17 | local opts = { 18 | style = "minimal", 19 | relative = "cursor", 20 | width = win_width, 21 | height = win_height, 22 | row = 1, 23 | col = 0 24 | } 25 | 26 | win = api.nvim_open_win(buf, true, opts) 27 | api.nvim_command('au BufWipeout exe " silent bwipeout! "'..border_buf) 28 | 29 | api.nvim_win_set_option(win, 'cursorline', true) 30 | 31 | api.nvim_buf_set_lines(buf, 0, -1, false, { 32 | util.center('Eswpoch'), '', '' 33 | }) 34 | api.nvim_buf_add_highlight(buf, -1, 'EswpochHeader', 0, 0, -1) 35 | api.nvim_win_set_cursor(win, {2, 0}) 36 | 37 | return buf 38 | end 39 | 40 | local function gen_divider() 41 | local result = "" 42 | for i=1, win_width do 43 | result = result.."=" 44 | end 45 | return result 46 | end 47 | 48 | local function close_window() 49 | api.nvim_win_close(win, true) 50 | end 51 | 52 | local function move_cursor(down) 53 | local new_pos = math.max(2, api.nvim_win_get_cursor(win)[1] - 1) 54 | 55 | if down then 56 | new_pos = math.min(6 + util.get_len(timezones), api.nvim_win_get_cursor(win)[1] + 1) 57 | end 58 | 59 | if new_pos == 6 and down then 60 | new_pos = 7 61 | elseif new_pos == 6 then 62 | new_pos = 5 63 | end 64 | api.nvim_win_set_cursor(win, {new_pos, 0}) 65 | end 66 | 67 | return { 68 | gen_divider = gen_divider, 69 | close_window = close_window, 70 | open_window = open_window, 71 | move_cursor = move_cursor, 72 | } 73 | -------------------------------------------------------------------------------- /lua/eswpoch/util.lua: -------------------------------------------------------------------------------- 1 | local api = vim.api 2 | 3 | local function get_len(table) 4 | local count = 0 5 | for _ in pairs(table) do 6 | count = count + 1 7 | end 8 | 9 | return count 10 | end 11 | 12 | local function center(str) 13 | local width = api.nvim_win_get_width(0) 14 | local shift = math.floor(width / 2) - math.floor(string.len(str) / 2) 15 | return string.rep(' ', shift) .. str 16 | end 17 | 18 | local function trim(s) 19 | return string.gsub(s, "^%s*(.-)%s*$", "%1") 20 | end 21 | 22 | local function split(s, delim) 23 | local result = {} 24 | local count = 1 25 | for i in string.gmatch(s, delim) do 26 | result[count] = i 27 | count = count + 1 28 | end 29 | return result 30 | end 31 | 32 | return { 33 | get_len = get_len, 34 | center = center, 35 | trim = trim, 36 | split = split 37 | } 38 | -------------------------------------------------------------------------------- /plugin/eswpoch.vim: -------------------------------------------------------------------------------- 1 | " Last Change: 2022 July 22 2 | " Maintainer: hlucco@gmail.com 3 | " License: MIT License 4 | 5 | "This line prevents loading the file twice 6 | if exists('g:loaded_eswpoch') | finish | endif 7 | 8 | let s:save_cpo = &cpo " save user coptions 9 | set cpo&vim " reset them to defaults 10 | 11 | command! Eswpoch lua require'eswpoch'.eswpoch() 12 | 13 | let &cpo = s:save_cpo " restore after 14 | unlet s:save_cpo 15 | 16 | let g:loaded_eswpoch = 1 17 | --------------------------------------------------------------------------------