├── .gitignore ├── LICENSE ├── README.md ├── completions └── mm.fish ├── docs ├── logo.png └── mm.gif └── functions ├── __mm_dependencies.fish └── mm.fish /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | playground.fish 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Esse Woods 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [![Demo](https://github.com/OakNinja/MakeMeFish/raw/master/docs/mm.gif)](https://github.com/OakNinja/MakeMeFish/raw/master/docs/mm.gif) 4 | 5 | MakeMeFish simplifies the usage of Makefiles by providing quick navigation and searching through make targets. 6 | 7 | ## Features 8 | 9 | - **Type ahead searching** - just write a few characters to filter out the targets you are looking for 10 | - **Preview** - When selecting a target, an excerpt of the target will be shown in the makefile, with match highlighting 11 | - **Snappy** - fzf-ingly fast! 12 | 13 | ## Prerequisities 14 | 15 | - Fish shell 3+ 16 | - fzf https://github.com/junegunn/fzf#installation 17 | 18 | Don't use fish? Get in touch if you want MakeMe support in your shell. 19 | 20 | ## Install using omf 21 | 22 | `omf install makeme` 23 | 24 | ## Install using fisher 25 | 26 | `fisher install oakninja/MakeMeFish` 27 | 28 | or 29 | 30 | `fisher install oakninja/MakeMeFish@next-release` 31 | 32 | to get the latest version. 33 | 34 | it's also possible to get the previous version by running 35 | 36 | `fisher install oakninja/MakeMeFish@previous-version` 37 | 38 | ## Install manually 39 | 40 | Download and copy `mm.fish` to `~/.config/fish/functions` 41 | 42 | or run 43 | 44 | `curl https://raw.githubusercontent.com/OakNinja/MakeMeFish/master/mm.fish?nocache --create-dirs -sLo ~/.config/fish/functions/mm.fish` 45 | 46 | ## Usage 47 | 48 | _Basic usage:_ 49 | type `mm`, if there is a Makefile in the current working directory, all targets will be listed. Start typing to filter targets. 50 | 51 | _Parameters:_ 52 | 53 | - `-h` or `--help` to print the help. 54 | - `-f ` to specify a makefile if you have several in the cwd, or if you have a non-standard name. 55 | - `-i` to start MakeMefish in interactive mode. In interactive mode, the selected target will be executed and you will then be returned to the selection prompt. Please note that executed commands won't be added to your command history. 56 | - `` eg. add an arbitrary keyword to start MakeMeFish with a pre-populated query (editable at runtime) 57 | 58 | ## Examples 59 | 60 | `mm build` will start `MakeMeFish` with an initial query which will filter for targets containing the substring `build`. 61 | Similarly, `mm foo bar` will filter on targets containing both `foo` and `bar` 62 | 63 | --- 64 | 65 | `mm -f MyFancyMakeFile` will start `MakeMeFish` and parse the file `MyFancyMakeFile` instead of trying to find a makefile with a GNU make standard name. 66 | 67 | --- 68 | 69 | `mm -i` will run `MakeMeFish` in interactive mode 70 | 71 | --- 72 | 73 | _All flags and parameters can be combined, and added in any order, eg._ 74 | 75 | `mm foo -i -f MyFancyMakeFile` is equivalent to `mm -f MyFancyMakeFile foo -i` 76 | -------------------------------------------------------------------------------- /completions/mm.fish: -------------------------------------------------------------------------------- 1 | complete -c mm -s f -r --description 'Usage: mm -f ' 2 | complete -c mm -s i -f --description 'Interactive mode' 3 | complete -c mm -s h -l help -f --description 'Display help' 4 | # complete -c mm -l install -f --description 'Install guide' Not implemented yet -------------------------------------------------------------------------------- /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OakNinja/MakeMeFish/7ea594574572a7fa2253d679a43ec57fa80aa440/docs/logo.png -------------------------------------------------------------------------------- /docs/mm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OakNinja/MakeMeFish/7ea594574572a7fa2253d679a43ec57fa80aa440/docs/mm.gif -------------------------------------------------------------------------------- /functions/__mm_dependencies.fish: -------------------------------------------------------------------------------- 1 | function __mm_confirm --description 'Confirm' --argument prompt 2 | if test -z "$prompt" 3 | set prompt "Continue?" 4 | end 5 | 6 | while true 7 | read -p 'echo -ne "$prompt ["; set_color green; echo -ne "y"; set_color normal; echo -ne "/"; set_color red; echo -ne "N"; set_color normal; echo -ne "]: "; ' -l confirm 8 | 9 | switch $confirm 10 | case Y y 11 | return 0 12 | case '' N n 13 | return 1 14 | end 15 | end 16 | end 17 | 18 | function __mm_echo --argument color --argument text --argument no_newline 19 | set_color $color; 20 | if test -n "$no_newline" 21 | echo -ne $text 22 | else 23 | echo $text 24 | end 25 | set_color normal; 26 | end 27 | 28 | function __mm_check_dependencies 29 | if type -q "fzf" 30 | return 0 31 | else 32 | return 1 33 | end 34 | end 35 | 36 | 37 | function __mm_install_dependencies 38 | if __mm_check_dependencies 39 | echo "" 40 | __mm_echo green "Dependencies already installed" 41 | echo "" 42 | return 0 43 | else 44 | echo "" 45 | echo "MakeMeFish is dependent of fzf - the command line fuzzy finder." 46 | if __mm_confirm "fzf is not installed. Would you like to install fzf?" 47 | switch (uname) 48 | case Linux Darwin 49 | if type -q "brew" 50 | if __mm_confirm "You are using brew - would you like to install fzf through brew?" 51 | echo (brew install fzf) 52 | return 0 53 | end 54 | end 55 | case FreeBSD NetBSD DragonFly 56 | echo (pkg install fzf) 57 | return 0 58 | case '*' 59 | echo "Unknown OS" 60 | end 61 | __mm_echo red "Could not install automatically." 62 | end 63 | echo -ne "Go to "; __mm_echo blue "https://github.com/junegunn/fzf#installation" 1; echo -ne " and follow the instructions for your environment." 64 | return 1 65 | end 66 | end 67 | 68 | function __mm_dependencies 69 | if __mm_check_dependencies 70 | return 0 71 | else 72 | if __mm_install_dependencies true 73 | return 0 74 | else 75 | return 1 76 | end 77 | end 78 | end -------------------------------------------------------------------------------- /functions/mm.fish: -------------------------------------------------------------------------------- 1 | function mm --description "MakeMeFish - List all Make targets in the Makefile of the current directory" 2 | 3 | set current_pos 1 4 | while test (count $argv) -ge $current_pos 5 | # Check if a help flag was passed to mm 6 | set help_flags -- -h --help 7 | if contains -- $argv[$current_pos] $help_flags 8 | echo "" 9 | echo " Usage:" 10 | echo " " (set_color green)"mm"(set_color normal) "will look for a Makefile in the order specified by GNU Make and list all targets in it." 11 | echo " " "To filter for a specific target, just start typing and targets will be filtered as you type." 12 | echo " " (set_color green)"mm "(set_color normal) "will start MakeMeFish with an initial, editable query" (set_color green)""(set_color normal) 13 | echo " " (set_color green)"mm -i"(set_color normal) "will start MakeMeFish in interactive mode. When a target is run, you will return to the selection menu." 14 | echo " " (set_color green)"mm -f "(set_color normal) "to specify what Makefile to load." 15 | echo " " "All flags can be combined in any order." 16 | echo "" 17 | return 0 18 | else if test $argv[$current_pos] = "-f" 19 | set current_pos (math "$current_pos+1") # skip the next 20 | set filename $argv[$current_pos] 21 | else if test $argv[$current_pos] = "-i" 22 | set interactive 1 23 | else 24 | if set -q initial_query 25 | set initial_query $initial_query $argv[$current_pos] 26 | else 27 | set initial_query $argv[$current_pos] 28 | end 29 | end 30 | set current_pos (math "$current_pos+1") 31 | end 32 | 33 | function __mm_get_makefile_name -a 'filename' 34 | if test -n "$filename" 35 | set makefile_filenames $filename 36 | else 37 | set makefile_filenames 'GNUmakefile' 'makefile' 'Makefile' 38 | end 39 | for filename in $makefile_filenames 40 | if test -f $filename 41 | echo $filename 42 | break 43 | end 44 | end 45 | end 46 | 47 | # Based on: 48 | # https://github.com/fish-shell/fish-shell/blob/8e418f5205106b11f83fa1956076a9b20c56f0f9/share/completions/make.fish 49 | # and 50 | # https://stackoverflow.com/a/26339924 51 | function __mm_parse_makefile -a 'filename' 52 | # Ensure correct locale set 53 | set -lx LC_ALL C 54 | 55 | set makeflags -f $filename 56 | 57 | # first awk merges any line that ends with a backslash with the next line 58 | if make --version 2>/dev/null | string match -q 'GNU*' 59 | make $makeflags -pRrq : 2>/dev/null | 60 | awk '{if (sub(/\\\$/,"")) printf "%s", $0; else print $0}' | 61 | awk -F: '/^# Files/,/^# Finished Make data base/ { 62 | if ($1 == "# Not a target") skip = 1; 63 | if ($1 !~ "^[#.\t]") { 64 | if (!skip) print $1; skip=0 65 | } 66 | }' 2>/dev/null 67 | else 68 | # BSD make 69 | make $makeflags -d g1 -rn >/dev/null 2>| awk -F, '/^#\*\*\* Input graph:/,/^$/ {if ($1 !~ "^#... ") {gsub(/# /,"",$1); print $1}}' 2>/dev/null 70 | end 71 | end 72 | 73 | function __mm_get_targets -a 'filename' 74 | set static_targets 75 | set file_targets 76 | set generated_targets 77 | 78 | set parsed_makefile (__mm_parse_makefile $filename | sort -f) 79 | for row in $parsed_makefile # Loop over all rows in the Makefile 80 | set row (string trim $row) 81 | if test -n "$row" # No blanks plz 82 | if test (string match -r '.\.|\/' $row) # this is a file or path 83 | set file_targets $file_targets $row 84 | else # grep the target and see if it's generated by a function or a true target 85 | set found_in_file (grep "$row:" $filename) 86 | if test -n "$found_in_file" 87 | set static_targets $static_targets $row # true target 88 | else 89 | set generated_targets $generated_targets $row # generated by function 90 | end 91 | end 92 | end 93 | end 94 | 95 | string split " " $static_targets $file_targets $generated_targets 96 | end 97 | 98 | function __mm_fzf_command -a 'filename' -a 'interactive' -a 'make_command' -a 'query' 99 | if [ $interactive -eq 1 ] 100 | set fzf_interactive "--bind \"enter:execute:$make_command {}; echo; echo 'Done'; sleep 1\"" 101 | end 102 | 103 | if test -n "$query" 104 | set fzf_query "--query=$query" 105 | end 106 | set fzf_opts "--read0 107 | $fzf_query 108 | $fzf_interactive 109 | --height 60% 110 | --layout=reverse 111 | --border 112 | --preview-window='right:60%' 113 | --preview='grep 114 | --color=always -A 10 -B 1 \^{}: $filename; or echo -GENERATED TARGET-'" 115 | 116 | set -q FZF_TMUX; or set FZF_TMUX 0 117 | set -q FZF_TMUX_HEIGHT; or set FZF_TMUX_HEIGHT 60% 118 | if [ $FZF_TMUX -eq 1 ] 119 | echo "fzf-tmux -d$FZF_TMUX_HEIGHT $fzf_opts" 120 | else 121 | echo "fzf $fzf_opts" 122 | end 123 | end 124 | 125 | if __mm_dependencies 126 | set custom_filename $filename 127 | set filename (__mm_get_makefile_name $filename) 128 | if test -z "$filename" 129 | echo 'No makefile found in the current working directory' 130 | else 131 | set targets (__mm_get_targets $filename) 132 | if test -n "$targets" 133 | if test -n "$custom_filename" 134 | set make_command "make -f $filename" 135 | else 136 | set make_command "make" 137 | end 138 | # Interactive? 139 | if test -n "$interactive"; and test $interactive -eq 1 140 | string join0 -- $targets | eval (__mm_fzf_command $filename 1 $make_command $initial_query) 141 | else 142 | string join0 -- $targets | eval (__mm_fzf_command $filename 0 $make_command $initial_query) | read -lz result # print targets as a list, pipe them to fzf, put the chosen command in $result 143 | set result (string trim -- $result) # Trim newlines and whitespace from the command 144 | and commandline -- "$make_command $result" # Prepend the make command 145 | commandline -f repaint # Repaint command line 146 | end 147 | else 148 | echo "No targets found in $filename" 149 | end 150 | end 151 | end 152 | 153 | end --------------------------------------------------------------------------------