1

I flip between different laptops and desktops a lot, some using external monitors. Maintaining different vimrc files is unmanageable. They become fragmented, and customizations that I come to rely on are suddenly available because I am working on a different system.

One such customization is the changing of the Vim window to a thin vertical window abutted against the right edge of the desktop. That way, I can take notes while partaking in video conferences. At present, I have a :GR command (mnemonic for "Go Right") which sizes and positions the Vim window appropriately, but using hard coded position and size numbers. If I can get the desktop size from within GVim, then I can calculate these parameters, which means that GR can be made to work regardless of what display I am using.

Is there a Vim command that can query the host windowing system for the desktop size? I primarily work with Windows 10, but I use Cygwin and X-windows.

4
  • At a guess, you could write a function that uses tests like has('win2unix') (Cygwin), (not sure about Windows itself or X-windows) and then, depending on what system, query a tool or file or whatever for the information you need. This is actually pretty common to do, I think
    – D. Ben Knoble
    Jul 12, 2022 at 18:40
  • @D.Ben Knoble: OK, thanks. Looks like there no insulation from the weird (and sometimes wonderful) world of X-windows. Jul 12, 2022 at 21:35
  • 1
    Does Cygwin and X-windows have the xrandr tool? If so, you can use it to get information about the current screen(s). For example, xrandr --query | grep ' connected primary' | grep -Eo '[0-9]+x[0-9]+' works on my Xorg system. You can use system() to call that from Vim: let [w, h] = system("xrandr --query | grep ' connected primary' | grep -Eo '[0-9]+x[0-9]+'")->trim()->split('x') (use str2nr() to convert from string to number) Jul 13, 2022 at 4:45
  • @MartinTournoij: Cygwin's X-windows does have xrandr. I will use your idea. Thanks! Did you want to post this as the answer? Jul 13, 2022 at 15:08

1 Answer 1

2

Since Cygwin comes with xrandr, you can use this to query information about a screen (all of this also works on e.g. Linux by the way). To get information you can use:

% xrandr --query | grep ' connected primary'
eDP-1 connected primary 1536x864+0+0 (normal left inverted right x axis y axis) 276mm x 155mm

Which shows I have a screen with a resolution of 1536x864 (it's an odd size because I scale it a bit from the default 1920x1080).

To use this in Vim you can use the system() function to call a shell command and matchlist() to "grep" the resolution out of there:

let [w, h] = system("xrandr --query | grep ' connected primary'")->
    matchlist('\d\+x\d\+')[0]->
    split('x')->
    map({_, v -> str2nr(v)})

A somewhat more complete version with some checks so it doesn't error out if the command doesn't exist:

fun Resolution() abort
    " Default, in case the command fails.
    let [dw, dh] = [1920, 1080]

    " Get resolution from xrandr, and match the resolution.
    let r = system("xrandr --query | grep ' connected primary'")
    if v:shell_error > 0
        return [dw, dh]
    endif

    let r = r->matchlist('\d\+x\d\+')
    if len(r) == 0
        return [dw, dh]
    endif

    " Split resolution by [width]x[height] and convert the string to a
    " number.
    let [w, h] = r[0]->split('x')->map({_, v -> str2nr(v)})
    if w == 0 || h == 0
        return [dw, dh]
    endif
    return [w, h]
endfun
4
  • Sorry for the delay in follow-up. I've had to spin up on a few vimscript concepts, such as lambda functions and curly braces. I haven't cracked the nut on the latter. I found the use of curly braces in :help eval, but it doesn't fit your use of it in map({...}). Without {...}, the underscore is explained in :help map(). Can you please provide a pointer to an explanation of the idiom map({_,...})? Thanks! Jul 23, 2022 at 21:51
  • @user2153235 map() calls a function for every item in the list and updates the value with whatever that function returns. You can write a "lambda" function as {arguments -> function body}. map` passes the array index and the value, in that order. So for some_list->map({ idx, value -> str2nr(value) }) it calls str2nr() for every value in the list (the return is implied with lambdas). I use the _ for the idx because we don't use that (which isn't "special" in VimScript IIRC, it's just a variable name). Jul 24, 2022 at 8:42
  • Thanks again, Martin. It all seems clear, and described in the Vim help. I was just getting side tracked by the missing 1st arguments for map when -> is used to invoke a function -- which is as it should be. I was also thrown by the need for map's 2nd argument to be a 2-argument function (index and value); theoretically, it seems that the mapping function should only be a function of each element's value, regardless of the index. From a practical standpoint, however, it's nice for the mapping function to be able to access the index. Jul 25, 2022 at 1:28
  • This has turned out to be way more complicated than I expected. I resize Gvim into a 60-column window abutted to the left edge of the desktop using set lines=999 columns=60 | let &lines = &lines -3 | winpos 0 50. The - 3 accounts for the window title bar and the Windows 10 task bar (I use Cygwin). To position the window along the right edge of the desktop, I then need to subtract the window width from desktop width, but it's tricky to get the window width without xdotool on Cygwin. I think I'll set this aside for now. Aug 12, 2022 at 22:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.