How can I generate a GUID in Vim?
Asked Answered
E

7

6

Vim doesn't have a built-in GUID generator.

For the project I'm working on, I can rely on Powershell being available, so the following gives me a GUID string:

[guid]::NewGuid().ToString()

I call this within a substitution, as follows:

%s/foo/\=system('[guid]::NewGuid().ToString()')[:2]/

While this works, it flashes up a window for each substitution and it's quite slow.

What I really want is a way to generate GUIDs within Vim, portably and quickly.

Elodea answered 10/9, 2012 at 10:55 Comment(3)
In your example, you're truncating the GUID to the first 3 characters ([:2]); that loses the uniqueness property, and turns the GUID into a basic (somewhat random) number. Are you sure you need a full GUID, or just an N-length random number?Herbarium
Sorry that should be [:-2] - just trimming the trailing rubbish offElodea
As noted here, you have to set set shellquote=\" and set shellxquote= to make system() work correctly with powershell.Floorage
V
13

If you can rely on Vim's Python scripting support being available

:pyx import uuid
:%s/foo/\=pyxeval('str(uuid.uuid4())')/

(If your Vim and Python are very old, use :py and pyeval() instead of :pyx and pyxeval().)

Vinia answered 10/9, 2012 at 11:10 Comment(3)
Unfortunately not. I'm on Windows, with neither Ruby nor Python necessarily available - doing it within Vim itself is the ideal.Elodea
Today I tried this solution but found that pyeval wasn't available, so ended up doing: :py vim.command("s/nguid/" + str(uuid.uuid4()) + "/g") ... and then repeating that, using a vim macro. Not ideal, but it worked well enough, thanks for the start on that.Elodea
this was very useful. I combined it with :nnoremap <Leader>s :%s/\<<C-r><C-w>\>/\=pyeval('str(uuid.uuid4()')/ and a marco and made short work of my particular problem. So all I really needed to do was \s and it replaced my search string with a uuidv4Hermon
H
3

If you don't want / cannot use a Vim language wrapping (e.g. to Python or Perl), you have to write a DLL wrapper for the Win32 UuidCreate() function and invoke that from Vim via libcall(). (The help says that you cannot directly invoke Windows system DLLs because the calling convention doesn't match.)

The wrapper is probably simple and easy to write, but you still need to compile a DLL and install that on each system.

Herbarium answered 10/9, 2012 at 11:34 Comment(0)
S
2

Replace

'[guid]::NewGuid().ToString()'

with

'powershell.exe -command "[guid]::NewGuid().ToString()"'

Does that help?

Surfboarding answered 10/9, 2012 at 11:1 Comment(1)
That's what I'm doing already - shell is set to powershell, but thanks.Elodea
R
2

I guess you just want replace the foo with random hex. If so, you can do like this:

M$ Windows:

%s/foo/\=printf("%04X",libcallnr("msvcrt.dll","rand",localtime()))[:2]/

For Unix:

%s/foo/\=printf("%04X",libcallnr("libc.so.6","rand",localtime()))[:2]/

This will be much faster than any other shell command.

Randers answered 11/9, 2012 at 6:29 Comment(3)
Nice example of using libcall(). Unfortunately, GUID != random number; the latter one doesn't guarantee the uniqueness.Herbarium
@IngoKarkat You are right, GUID isn't a random number. While by considering the use case: it only use the first 3 hex of GUID. And the implementation of GUID. So i just guess that it can be replace by a random number generator. :)Randers
Good catch; I didn't fully realize the GUID output is truncated. That makes your solution a good alternative; +1Herbarium
T
2

Assuming you have python in your path, the following are some mappings to insert or append a UUID at the cursor. It should be platform-agnostic.

" Insert GUID
nnoremap <silent><leader>ig "=system('python -c "import uuid; print(uuid.uuid4(), end=\"\");"')<CR>P

" Append GUID
nnoremap <silent><leader>ag "=system('python -c "import uuid; print(uuid.uuid4(), end=\"\");"')<CR>p

How it works:

  • python -c "import uuid; print(uuid.uuid4(), end=\"\");"' - a shell one-liner to print a UUID to STDOUT without a newline, using python and the uuid module.
  • "= - " tells vim to assign the next value to a specified register, in this case the expression register: =
  • system(...) - this shells out and redirects the output for use in the assignment to the register
  • <CR>P or <CR>p - evaluate and paste the register at the cursor (insert, append, respectively)
Towrope answered 2/12, 2020 at 23:27 Comment(0)
H
1

On Windows, the system() command pops up a command window (usually in the background, though). One way to avoid this is to use a language binding compiled into Vim, e.g. Python:

:python import uuid, vim; vim.command("let g:uuid = '" + str(uuid.uuid1()) + "'

This is both faster and avoids the popup, but does require a Python installation and a Vim that has Python support; you can probably come up with a similar Perl or Ruby implementation, if for some reason you prefer another language. Unfortunately, there is no PowerShell language binding yet.

Herbarium answered 10/9, 2012 at 11:17 Comment(0)
T
1

I got here because the question-title asks how to create an UUID, however the question-text actually wants to replace existing textblocks with a newly created UUID.

Marius Gedminas' Answer got me very far, and if anyone else needs to create and insert an UUID, here is how:

function! Guid()
python << EOF
import uuid, vim
vim.command("normal i" + str(uuid.uuid4()) )
EOF
endfunction

If you want to map it to <alt+G>: map <m-g> :call Guid() <cr>

(In case your Gvim crashes upon invoking Python, read this)

Typehigh answered 13/11, 2017 at 13:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.