https://extensions.gnome.org/extension/1336/run-or-raise/
I assume the run-or-raise style as the most efficient way of handling windows. No more searching for your favourite program in a long menu, no more clicking on the icons. If the program already runs it will get the focus, else we launch it.
Several years ago, OS creators finally realized that efficiency and let the users run-or-raise programs on the taskbar or dock by Super+number shortcuts. But what if you use more programs than nine? What if you do not want the unnecessary taskbar to occupy the precious place on the screen?
With the emergence of Wayland over X.org, we can't reliably use good old xbindkeys and jumpapp to master shortcuts. Here is a gnome-shell extension that let you migrate your favourite shortcuts to the shortcuts.conf file.
OR
/home/$USER/.local/share/gnome-shell/extensions/run-or-raise@edvard.czgnome-extensions-app panelshortcuts.conf file to use your own shortcutsshortcuts.conf, and disable and enable.On the first run, ~/.config/run-or-raise/shortcuts.conf gets created from shortcuts.default if not exists. There you define your own shortcuts.
Note that if an argument should contain a comma, use double quotes around.
<Super>i,"/usr/bin/cmd comma, needed",,application_title
When you trigger a shortcut it lets you cycle amongst open instances of the application or if not found, launches a new instance. The file consists of shortcuts in the following form:
shortcut[ shortcut][:mode],command,[wm_class],[title]
Shortcut consists of an arbitrary number of modifiers (angle brackets) and a character, like <Shift>a, <Shift><Super>a, simple a or <Super>slash. Character might be either a keysym (a, acute) or a keycode in the hex format, ex: letter a with the keycode 38 is noted 0x26.
For custom shortcuts, I recommended using mostly combinations containing the modifier <Super> as this normally indicates global shortcuts. In the opposition to <Shift> which is semantically reserved for letter case a/A, <Alt> for underlined letters and <Ctrl> for various application-defined actions.
Possible modifiers:
<Shift>, <Alt>, <Meta>, <Ctrl> (<Primary>), <Super> known as Win, <Hyper><ISO_Level5_Shift> (I really recommend mapping this modifier instead of Caps Lock)<Mod1>, <Mod2>, <Mod3>, <Mod4>, <Mod5>xmodmap to see the overview of the keys that are mapped to modsxev/wev to determine key symbols you have mapped<ISO_Level3_Shift> that is bound to mod5, you would use <Mod5> to create its shortcuts<Super> and <Hyper> on mod4. You bind them all by <Super>i, <Hyper>i, <Mod4>i shortcuts. As they are the same on the internal Gnome-level, only the first shortcut grabs the accelerator, the latter defined will not work. For more information, consult Gnome/Mutter/core/meta-accel-parse.c source code.<Num_Lock>, <Num_Lock_OFF><Caps_Lock>, <Caps_Lock_OFF><Scroll_Lock>, <Scroll_Lock_OFF> (Scroll_Lock might not be available in Wayland session, hence might be removed in the future)Multiple actions may be registered to the same shortcut (a shortcut appears on multiple lines). They get lauched sequentionally.
<Super>e,notify-send appears first
<Super>e,notify-send appears second
Layered shortcuts are possible. After the shortcut is hit, you may specify one or more shortcuts to be hit in order to trigger the action.
<Super>e a,notify-send Launched a
<Super>e b,notify-send Launched b
<Super>e c d,notify-send Launched cd
<Super>e c e,notify-send Launched ce
<Super>g,notify-send Launched "<Super>g"
<Super>e <Super>g,notify-send Launched "<Super>e and then <Super>g"
<Super>e <Super>e e,notify-send Launched "<Super>e e"
If you need to discover a keysym (or at xkbcommon.org), I recommend the xev/wev program again.
<Super>grave,notify-send "Using backtick in the shortcut: `"
When in trouble, use keycode in hex form instead of a keysym. In this example, we recognize 49 is the keycode of the backtick (31 in hex).
$ wev # type backtick key
[14: wl_keyboard] key: serial: 23425; time: 8592750; key: 49; state: 0 (released) sym: grave (96), utf8: ''
Hence the hex form is 0x31:
<Super>0x31,notify-send "Using backtick keycode in the shortcut: `"
command, wm_class and titlecommand can be either:
wm_class and title arguments are optional and case-sensitivewm_class nor title is set, lower-cased command is compared with lower-cased windows' wm_classes and titlestitle and wm_classThe title is shown in the header area. Since the title tends to be dynamically changed by the application, you can use wm_class which compares to both parts (both WM_CLASS_NAME and WM_CLASS_INSTANCE) of this window property.
How to know the wm_class?
Just use the xprop program and filter the WM_CLASS line:
$ xprop
# hit the mail window with the mouse cursor and get:
WM_CLASS(STRING) = "mail.google.com__mail_u_0", "Google-chrome"
The first string mail.google.com__mail_u_0 is more specific WM_CLASS_INSTANCE, the second Google-chrome is more stable WM_CLASS_NAME.
Alternatively, you can use the looking glass tool (at least on Ubuntu 17.10+) by launching Alt+f2 / lg / "Windows" tab. There, you see WM_CLASS_NAME listed as wmclass. To get the WM_CLASS_INSTANCE, click on a window title / button "Insert" / go back to the "Evaluator" tab and refer the window via the inserted value r like: r(0).get_wm_class_instance().
I found no easier solution for the moment.
Following shortcut will firstly launch mail window in an application mode. Later on, it will cycle all windows that have mail.google.com in the wm_class. (Which is what we want here.)
<Super>e,/opt/google/chrome/google-chrome --app=https://mail.google.com/mail/u/0,mail.google.com,
In an opposite manner, this would cycle all Chrome windows. (Which is not what we want.)
<Super>e,/opt/google/chrome/google-chrome --app=https://mail.google.com/mail/u/0,Google-chrome,
And finally, using the title part rather than the wm_class part, this would cycle all windows that have Gmail in the title. On one side this would include windows just mentioning Gmail (bad). On the other side when somebody writes you to the chat, the window title changes and the shortcut would open another Gmail instance (even worse).
<Super>e,/opt/google/chrome/google-chrome --app=https://mail.google.com/mail/u/0,,Gmail
Modes are special instructions that let you change the triggered behaviour. Some of them can be turned on globally in the extension preferences (so you do not have to specify them for every single shortcut if you need them everywhere).
You can combine multiple modes by appending a colon. On the first hit, we register a window. On the second, we raise it while bringing to the active workspace.
<Super>i:raise-or-register:move-window-to-active-workspace
isolate-workspaceSwitch windows on the active workspace only
# cycles Firefox instances in the current workspace
<Super>KP_1:isolate-workspace,firefox,
minimize-when-unfocusedMinimizes your target when unfocusing
switch-back-when-focusedSwitch back to the previous window when focused. If a shortcut has no but a single window to cycle, it focuses last used window instead of doing nothing.
To consider windows on all monitors (instead of only the current monitor), use switch-back-when-focused(all_monitors).
move-window-to-active-workspaceMove window to current workspace before focusing. If the window is on a different workspace, moves the window to the workspace you're currently viewing.
center-mouse-to-focused-windowMoves mouse to the center of the newly focused window (unless cursor is not in the window area already).
always-runBoth runs the command and raises a window
# Runs a command whether a window with wm_class 'kitty' is already open or not
<Super>t:always-run,my_tmux_script.sh,kitty
run-onlySince it is very convenient to use a single file for all of your shortcuts (backup, migration to another system...), you can define standard shortcuts as well. These commands just get launched whenever the keys are hit and never raises a window. The keyword is implicit if no superfluous commas are noted in the line: shortcut,command
# this line will launch the notify-send command.
<Super>y,notify-send Hello world
# this line WILL raise a Firefox window or launches a command (note a trailing comma)
<Super>f,firefox,
# these equivalent lines will always launch a new Firefox instance, never raising a window
<Super>f,firefox
<Super>f:run-only,firefox,
register(0)Register the current window dynamically to be re-raised by using raise mode with the same number in the argument
<Super><Ctrl>KP_0:register(1)
<Super>KP_0:raise(1)
<Super><Ctrl>KP_Delete:register(2)
<Super>KP_Delete:raise(2)
raise(0)Raise the windows previously registered by the register keyword
raise-or-registerIf nothing registered yet, register the current window. Next time raise it unless the window is closed. In the example, we set Super+i and Super+o to bind a window each.
<Super>i:raise-or-register
<Super>o:raise-or-register
raise-or-register(0)If nothing has been registered yet, register the current window. Next time, raise it, unless the window is closed or has been remapped with register(the same number). Thus, it is a combination of register, raise, and raise-or-register.
verbosePopups debug details via notify-send. (Normally it seems launched commands pipe the output to the /var/log/syslog.)
In the extension settings, you may allow listening on DBus. Then, you can invoke the commands from the shell. The following example would start a firefox instance. Note there is no shortcut mentioned as the shortcuts are ignored.
$ gdbus call --session --dest org.gnome.Shell --object-path /org/gnome/Shell/Extensions/RunOrRaise --method org.gnome.Shell.Extensions.RunOrRaise.Call ",firefox"
('Success',)
This line cycles any firefox window (matched by "firefox" in the window title) OR if not found, launches a new firefox instance:
<Super>f,firefox,,
This line starts gnome-terminal using it's .desktop file:
<Super>f,org.gnome.Terminal.desktop,,
This line cycles any open gnome-terminal OR if not found, launches a new one.
<Super>r,gnome-terminal,,
If you want to be sure that your browser won't be focused when you're on the page having "gnome-terminal" in the title, you may want to match running application by wm_class = Gnome-terminal (Ubuntu on Xorg) or by wm_class = gnome-terminal-server (Ubuntu on Wayland or Arch)... just check yourself by Alt+F2/lg/Windows everytime wm_class is needed.
<Super>r,gnome-terminal,Gnome-terminal,
You may use regular expressions in title or wm_class. Just put the expression between slashes.
E.g. to jump to pidgin conversation window you may use this line
(that mean any windows of wm_class Pidgin, not containing the title Buddy List)"
<Super>KP_1,pidgin,Pidgin,/^((?!Buddy List).)*$/
To match Google-chrome and not Google-chrome-beta, help yourself with $ sign to mark the end of matched text.
<Super>KP_3,gtk-launch google-chrome.desktop,/Google-chrome$/,
<Super><Shift>KP_3,gtk-launch google-chrome-beta.desktop,Google-chrome-beta,
Another occasion you'd use regulars would be the case when you'd like to have multiple applications on single keystroke. In the following example, shortcut Super+Ctrl+(Numpad)4 focuses an IDE editor, either NetBeans or PyCharm. Because I'm mainly using NetBeans but for Python language I prefer PyCharm, I was wrong too often till I set single keystroke for both. (However, when no IDE is open, for launching NetBeans I use numpad and for PyCharm the 4 on the 4th row of keyboard.)
<Super><Ctrl>4,/opt/pycharm-community-2017.2.4/bin/pycharm.sh,,/(NetBeans IDE|PyCharm)/
<Super><Ctrl>KP_4,/opt/netbeans/bin/netbeans,,/(NetBeans IDE|PyCharm)/
To run a command as a sudo, try simple pkexec program that raises the password dialogue. For a repetitive task, familiarise yourself with the system sudoers file.
<Super>r,bash -c 'notify-send "Root folder" "`pkexec ls /root/`"'
gnome-extensions disable run-or-raise@edvard.cz && gnome-extensions enable run-or-raise@edvard.czNote that GNOME Shell supports a basic run-or-raise workflow out of the box! To enjoy a basic run-or-raise with no extension:
Activities → Right click on open app → Pin to Dash).N is 1..9): gsettings set "org.gnome.shell.keybindings" "switch-to-application-N" "['<Your+Command>']".Caveats: Limited to 9 apps; no wmclass, regex, layered shortcuts, or modes support. Limited to static StartupWMClass in XDG .desktop files.
How to implement a new mode?
Mode class in the mode.js filemake compileAction.trigger method, by checking if the settings is on (either locally per shortcut or globally) by this.mode.get(Mode.KEYWORD)
When tired of logging out to refresh the code, launch a new wayland session ex by:
(sleep 1 && gnome-extensions disable run-or-raise@edvard.cz & ) && dbus-run-session -- gnome-shell --nested --wayland && gnome-extensions enable run-or-raise@edvard.cz
What does this command do? Note that the extension must be running in the main session in order to be started in the nested session too. So after a second, we disable it in the main session to not interfere with the nested instance of the extension: They share the same shortcuts and the main would prevail. When the nested session is over, enable it in the main session again.
JavaScript
96.3%
Shell
2.3%
Makefile
1.5%
https://extensions.gnome.org/extension/1336/run-or-raise/
I assume the run-or-raise style as the most efficient way of handling windows. No more searching for your favourite program in a long menu, no more clicking on the icons. If the program already runs it will get the focus, else we launch it.
Several years ago, OS creators finally realized that efficiency and let the users run-or-raise programs on the taskbar or dock by Super+number shortcuts. But what if you use more programs than nine? What if you do not want the unnecessary taskbar to occupy the precious place on the screen?
With the emergence of Wayland over X.org, we can't reliably use good old xbindkeys and jumpapp to master shortcuts. Here is a gnome-shell extension that let you migrate your favourite shortcuts to the shortcuts.conf file.
OR
/home/$USER/.local/share/gnome-shell/extensions/run-or-raise@edvard.czgnome-extensions-app panelshortcuts.conf file to use your own shortcutsshortcuts.conf, and disable and enable.On the first run, ~/.config/run-or-raise/shortcuts.conf gets created from shortcuts.default if not exists. There you define your own shortcuts.
Note that if an argument should contain a comma, use double quotes around.
<Super>i,"/usr/bin/cmd comma, needed",,application_title
When you trigger a shortcut it lets you cycle amongst open instances of the application or if not found, launches a new instance. The file consists of shortcuts in the following form:
shortcut[ shortcut][:mode],command,[wm_class],[title]
Shortcut consists of an arbitrary number of modifiers (angle brackets) and a character, like <Shift>a, <Shift><Super>a, simple a or <Super>slash. Character might be either a keysym (a, acute) or a keycode in the hex format, ex: letter a with the keycode 38 is noted 0x26.
For custom shortcuts, I recommended using mostly combinations containing the modifier <Super> as this normally indicates global shortcuts. In the opposition to <Shift> which is semantically reserved for letter case a/A, <Alt> for underlined letters and <Ctrl> for various application-defined actions.
Possible modifiers:
<Shift>, <Alt>, <Meta>, <Ctrl> (<Primary>), <Super> known as Win, <Hyper><ISO_Level5_Shift> (I really recommend mapping this modifier instead of Caps Lock)<Mod1>, <Mod2>, <Mod3>, <Mod4>, <Mod5>xmodmap to see the overview of the keys that are mapped to modsxev/wev to determine key symbols you have mapped<ISO_Level3_Shift> that is bound to mod5, you would use <Mod5> to create its shortcuts<Super> and <Hyper> on mod4. You bind them all by <Super>i, <Hyper>i, <Mod4>i shortcuts. As they are the same on the internal Gnome-level, only the first shortcut grabs the accelerator, the latter defined will not work. For more information, consult Gnome/Mutter/core/meta-accel-parse.c source code.<Num_Lock>, <Num_Lock_OFF><Caps_Lock>, <Caps_Lock_OFF><Scroll_Lock>, <Scroll_Lock_OFF> (Scroll_Lock might not be available in Wayland session, hence might be removed in the future)Multiple actions may be registered to the same shortcut (a shortcut appears on multiple lines). They get lauched sequentionally.
<Super>e,notify-send appears first
<Super>e,notify-send appears second
Layered shortcuts are possible. After the shortcut is hit, you may specify one or more shortcuts to be hit in order to trigger the action.
<Super>e a,notify-send Launched a
<Super>e b,notify-send Launched b
<Super>e c d,notify-send Launched cd
<Super>e c e,notify-send Launched ce
<Super>g,notify-send Launched "<Super>g"
<Super>e <Super>g,notify-send Launched "<Super>e and then <Super>g"
<Super>e <Super>e e,notify-send Launched "<Super>e e"
If you need to discover a keysym (or at xkbcommon.org), I recommend the xev/wev program again.
<Super>grave,notify-send "Using backtick in the shortcut: `"
When in trouble, use keycode in hex form instead of a keysym. In this example, we recognize 49 is the keycode of the backtick (31 in hex).
$ wev # type backtick key
[14: wl_keyboard] key: serial: 23425; time: 8592750; key: 49; state: 0 (released) sym: grave (96), utf8: ''
Hence the hex form is 0x31:
<Super>0x31,notify-send "Using backtick keycode in the shortcut: `"
command, wm_class and titlecommand can be either:
wm_class and title arguments are optional and case-sensitivewm_class nor title is set, lower-cased command is compared with lower-cased windows' wm_classes and titlestitle and wm_classThe title is shown in the header area. Since the title tends to be dynamically changed by the application, you can use wm_class which compares to both parts (both WM_CLASS_NAME and WM_CLASS_INSTANCE) of this window property.
How to know the wm_class?
Just use the xprop program and filter the WM_CLASS line:
$ xprop
# hit the mail window with the mouse cursor and get:
WM_CLASS(STRING) = "mail.google.com__mail_u_0", "Google-chrome"
The first string mail.google.com__mail_u_0 is more specific WM_CLASS_INSTANCE, the second Google-chrome is more stable WM_CLASS_NAME.
Alternatively, you can use the looking glass tool (at least on Ubuntu 17.10+) by launching Alt+f2 / lg / "Windows" tab. There, you see WM_CLASS_NAME listed as wmclass. To get the WM_CLASS_INSTANCE, click on a window title / button "Insert" / go back to the "Evaluator" tab and refer the window via the inserted value r like: r(0).get_wm_class_instance().
I found no easier solution for the moment.
Following shortcut will firstly launch mail window in an application mode. Later on, it will cycle all windows that have mail.google.com in the wm_class. (Which is what we want here.)
<Super>e,/opt/google/chrome/google-chrome --app=https://mail.google.com/mail/u/0,mail.google.com,
In an opposite manner, this would cycle all Chrome windows. (Which is not what we want.)
<Super>e,/opt/google/chrome/google-chrome --app=https://mail.google.com/mail/u/0,Google-chrome,
And finally, using the title part rather than the wm_class part, this would cycle all windows that have Gmail in the title. On one side this would include windows just mentioning Gmail (bad). On the other side when somebody writes you to the chat, the window title changes and the shortcut would open another Gmail instance (even worse).
<Super>e,/opt/google/chrome/google-chrome --app=https://mail.google.com/mail/u/0,,Gmail
Modes are special instructions that let you change the triggered behaviour. Some of them can be turned on globally in the extension preferences (so you do not have to specify them for every single shortcut if you need them everywhere).
You can combine multiple modes by appending a colon. On the first hit, we register a window. On the second, we raise it while bringing to the active workspace.
<Super>i:raise-or-register:move-window-to-active-workspace
isolate-workspaceSwitch windows on the active workspace only
# cycles Firefox instances in the current workspace
<Super>KP_1:isolate-workspace,firefox,
minimize-when-unfocusedMinimizes your target when unfocusing
switch-back-when-focusedSwitch back to the previous window when focused. If a shortcut has no but a single window to cycle, it focuses last used window instead of doing nothing.
To consider windows on all monitors (instead of only the current monitor), use switch-back-when-focused(all_monitors).
move-window-to-active-workspaceMove window to current workspace before focusing. If the window is on a different workspace, moves the window to the workspace you're currently viewing.
center-mouse-to-focused-windowMoves mouse to the center of the newly focused window (unless cursor is not in the window area already).
always-runBoth runs the command and raises a window
# Runs a command whether a window with wm_class 'kitty' is already open or not
<Super>t:always-run,my_tmux_script.sh,kitty
run-onlySince it is very convenient to use a single file for all of your shortcuts (backup, migration to another system...), you can define standard shortcuts as well. These commands just get launched whenever the keys are hit and never raises a window. The keyword is implicit if no superfluous commas are noted in the line: shortcut,command
# this line will launch the notify-send command.
<Super>y,notify-send Hello world
# this line WILL raise a Firefox window or launches a command (note a trailing comma)
<Super>f,firefox,
# these equivalent lines will always launch a new Firefox instance, never raising a window
<Super>f,firefox
<Super>f:run-only,firefox,
register(0)Register the current window dynamically to be re-raised by using raise mode with the same number in the argument
<Super><Ctrl>KP_0:register(1)
<Super>KP_0:raise(1)
<Super><Ctrl>KP_Delete:register(2)
<Super>KP_Delete:raise(2)
raise(0)Raise the windows previously registered by the register keyword
raise-or-registerIf nothing registered yet, register the current window. Next time raise it unless the window is closed. In the example, we set Super+i and Super+o to bind a window each.
<Super>i:raise-or-register
<Super>o:raise-or-register
raise-or-register(0)If nothing has been registered yet, register the current window. Next time, raise it, unless the window is closed or has been remapped with register(the same number). Thus, it is a combination of register, raise, and raise-or-register.
verbosePopups debug details via notify-send. (Normally it seems launched commands pipe the output to the /var/log/syslog.)
In the extension settings, you may allow listening on DBus. Then, you can invoke the commands from the shell. The following example would start a firefox instance. Note there is no shortcut mentioned as the shortcuts are ignored.
$ gdbus call --session --dest org.gnome.Shell --object-path /org/gnome/Shell/Extensions/RunOrRaise --method org.gnome.Shell.Extensions.RunOrRaise.Call ",firefox"
('Success',)
This line cycles any firefox window (matched by "firefox" in the window title) OR if not found, launches a new firefox instance:
<Super>f,firefox,,
This line starts gnome-terminal using it's .desktop file:
<Super>f,org.gnome.Terminal.desktop,,
This line cycles any open gnome-terminal OR if not found, launches a new one.
<Super>r,gnome-terminal,,
If you want to be sure that your browser won't be focused when you're on the page having "gnome-terminal" in the title, you may want to match running application by wm_class = Gnome-terminal (Ubuntu on Xorg) or by wm_class = gnome-terminal-server (Ubuntu on Wayland or Arch)... just check yourself by Alt+F2/lg/Windows everytime wm_class is needed.
<Super>r,gnome-terminal,Gnome-terminal,
You may use regular expressions in title or wm_class. Just put the expression between slashes.
E.g. to jump to pidgin conversation window you may use this line
(that mean any windows of wm_class Pidgin, not containing the title Buddy List)"
<Super>KP_1,pidgin,Pidgin,/^((?!Buddy List).)*$/
To match Google-chrome and not Google-chrome-beta, help yourself with $ sign to mark the end of matched text.
<Super>KP_3,gtk-launch google-chrome.desktop,/Google-chrome$/,
<Super><Shift>KP_3,gtk-launch google-chrome-beta.desktop,Google-chrome-beta,
Another occasion you'd use regulars would be the case when you'd like to have multiple applications on single keystroke. In the following example, shortcut Super+Ctrl+(Numpad)4 focuses an IDE editor, either NetBeans or PyCharm. Because I'm mainly using NetBeans but for Python language I prefer PyCharm, I was wrong too often till I set single keystroke for both. (However, when no IDE is open, for launching NetBeans I use numpad and for PyCharm the 4 on the 4th row of keyboard.)
<Super><Ctrl>4,/opt/pycharm-community-2017.2.4/bin/pycharm.sh,,/(NetBeans IDE|PyCharm)/
<Super><Ctrl>KP_4,/opt/netbeans/bin/netbeans,,/(NetBeans IDE|PyCharm)/
To run a command as a sudo, try simple pkexec program that raises the password dialogue. For a repetitive task, familiarise yourself with the system sudoers file.
<Super>r,bash -c 'notify-send "Root folder" "`pkexec ls /root/`"'
gnome-extensions disable run-or-raise@edvard.cz && gnome-extensions enable run-or-raise@edvard.czNote that GNOME Shell supports a basic run-or-raise workflow out of the box! To enjoy a basic run-or-raise with no extension:
Activities → Right click on open app → Pin to Dash).N is 1..9): gsettings set "org.gnome.shell.keybindings" "switch-to-application-N" "['<Your+Command>']".Caveats: Limited to 9 apps; no wmclass, regex, layered shortcuts, or modes support. Limited to static StartupWMClass in XDG .desktop files.
How to implement a new mode?
Mode class in the mode.js filemake compileAction.trigger method, by checking if the settings is on (either locally per shortcut or globally) by this.mode.get(Mode.KEYWORD)
When tired of logging out to refresh the code, launch a new wayland session ex by:
(sleep 1 && gnome-extensions disable run-or-raise@edvard.cz & ) && dbus-run-session -- gnome-shell --nested --wayland && gnome-extensions enable run-or-raise@edvard.cz
What does this command do? Note that the extension must be running in the main session in order to be started in the nested session too. So after a second, we disable it in the main session to not interfere with the nested instance of the extension: They share the same shortcuts and the main would prevail. When the nested session is over, enable it in the main session again.
JavaScript
96.3%
Shell
2.3%
Makefile
1.5%