#!/usr/bin/env ruby require 'open-uri' require 'open3' require 'yaml' require 'fileutils' Dir.chdir(__dir__) BASE_URL = 'https://raw.githubusercontent.com/github/linguist/master' DIRS = { default: %w(syntax indent compiler autoload ftplugin ctags after/syntax after/indent after/ftplugin), all: %w(syntax indent compiler autoload ftplugin after extras ctags), basic: %w(syntax compiler indent after/syntax after/indent), syntax: %w(syntax indent after/syntax after/indent), noafter: %w(syntax compiler indent autoload ftplugin), javascript: %w(syntax indent compiler autoload ftplugin ctags after/syntax after/indent after/ftplugin extras), go: %w(autoload/go/config.vim syntax compiler indent after/syntax after/indent) } PACKAGES = [ { name: "acpiasl", remote: "martinlroth/vim-acpi-asl", }, { name: "ansible", remote: "pearofducks/ansible-vim", }, { name: "apiblueprint", remote: "sheerun/apiblueprint.vim", }, { name: "applescript", remote: "mityu/vim-applescript", dirs: DIRS[:syntax] }, { name: "arduino", remote: "sudar/vim-arduino-syntax", }, { name: "asciidoc", remote: "asciidoc/vim-asciidoc", }, { name: "autohotkey", remote: "hnamikaw/vim-autohotkey", }, { name: "blade", remote: "jwalton512/vim-blade", }, { name: "brewfile", remote: "bfontaine/Brewfile.vim", }, { name: "c++11", remote: "octol/vim-cpp-enhanced-highlight", }, { name: "c/c++", remote: "vim-jp/vim-cpp", }, { name: "caddyfile", remote: "isobit/vim-caddyfile", }, { name: "carp", remote: "hellerve/carp-vim", }, { name: "cjsx", remote: "mtscout6/vim-cjsx", }, { name: "clojure", remote: "guns/vim-clojure-static", }, { name: "cmake", remote: "pboettch/vim-cmake-syntax", }, { name: "coffee-script", remote: "kchmck/vim-coffee-script", dirs: DIRS[:noafter] }, { name: "cql", remote: "elubow/cql-vim", }, { name: "cryptol", remote: "victoredwardocallaghan/cryptol.vim", }, { name: "crystal", remote: "rhysd/vim-crystal", }, { name: "csv", remote: "chrisbra/csv.vim", }, { name: "cucumber", remote: "tpope/vim-cucumber", }, { name: "cue", remote: "mgrabovsky/vim-cuesheet", }, { name: "dart", remote: "dart-lang/dart-vim-plugin", }, { name: "dhall", remote: "vmchale/dhall-vim", }, { name: "dlang", remote: "JesseKPhillips/d.vim", }, { name: "dockerfile", remote: "ekalinin/Dockerfile.vim", }, { name: "elixir", remote: "elixir-lang/vim-elixir", }, { name: "elm", remote: "andys8/vim-elm-syntax", }, { name: "emberscript", remote: "yalesov/vim-ember-script", }, { name: "emblem", remote: "yalesov/vim-emblem", }, { name: "erlang", remote: "vim-erlang/vim-erlang-runtime", }, { name: "fennel", remote: "bakpakin/fennel.vim", }, { name: "ferm", remote: "vim-scripts/ferm.vim", }, { name: "fish", remote: "georgewitteman/vim-fish", }, { name: "flatbuffers", remote: "dcharbon/vim-flatbuffers", }, { name: "fsharp", remote: "ionide/Ionide-vim", dirs: DIRS[:basic] }, { name: "gdscript", remote: "calviken/vim-gdscript3", dirs: DIRS[:syntax] }, { name: "git", remote: "tpope/vim-git", }, { name: "glsl", remote: "tikhomirov/vim-glsl", dirs: DIRS[:noafter] }, { name: "gmpl", remote: "maelvalais/gmpl.vim", }, { name: "gnuplot", remote: "vim-scripts/gnuplot-syntax-highlighting", }, { name: "go", remote: "fatih/vim-go", dirs: DIRS[:go] }, { name: "graphql", remote: "jparise/vim-graphql", dirs: DIRS[:all] }, { name: "gradle", remote: "tfnico/vim-gradle", }, { name: "haml", remote: "sheerun/vim-haml", }, { name: "handlebars", remote: "sheerun/vim-mustache-handlebars", }, { name: "haproxy", remote: "CH-DanReif/haproxy.vim", }, { name: "haskell", remote: "neovimhaskell/haskell-vim", }, { name: "haxe", remote: "yaymukund/vim-haxe", }, { name: "hcl", remote: "b4b4r07/vim-hcl", }, { name: "helm", remote: "towolf/vim-helm", }, { name: "hive", remote: "zebradil/hive.vim", }, { name: "html5", remote: "othree/html5.vim", }, { name: "i3", remote: "mboughaba/i3config.vim", }, { name: "icalenadr", remote: "chutzpah/icalendar.vim", }, { name: "idris", remote: "idris-hackers/idris-vim", }, { name: "ion", remote: "vmchale/ion-vim", }, { name: "javascript", remote: "pangloss/vim-javascript", dirs: DIRS[:javascript] }, { name: "jenkins", remote: "martinda/Jenkinsfile-vim-syntax", }, { name: "jinja", remote: "lepture/vim-jinja", }, { name: "jq", remote: "vito-c/jq.vim", }, { name: "json5", remote: "GutenYe/json5.vim", }, { name: "json", remote: "elzr/vim-json", }, { name: "jsonnet", remote: "google/vim-jsonnet", }, { name: "jst", remote: "briancollins/vim-jst", }, { name: "jsx", remote: "MaxMEllon/vim-jsx-pretty", dirs: DIRS[:all] }, { name: "julia", remote: "JuliaEditorSupport/julia-vim", }, { name: "kotlin", remote: "udalov/kotlin-vim", }, { name: "ledger", remote: "ledger/vim-ledger", dirs: DIRS[:basic] }, { name: "less", remote: "groenewege/vim-less", dirs: DIRS[:noafter] }, { name: "lilypond", remote: "anowlcalledjosh/vim-lilypond", }, { name: "livescript", remote: "gkz/vim-ls", }, { name: "llvm", remote: "rhysd/vim-llvm", }, { name: "log", remote: "MTDL9/vim-log-highlighting", }, { name: "lua", remote: "tbastos/vim-lua", }, { name: "mako", remote: "sophacles/vim-bundle-mako", }, { name: "markdown", remote: "plasticboy/vim-markdown", dirs: DIRS[:noafter] }, { name: "mathematica", remote: "voldikss/vim-mma", }, { name: "mdx", remote: "jxnblk/vim-mdx-js", }, { name: "meson", remote: "mesonbuild/meson:data/syntax-highlighting/vim", dirs: DIRS[:all] }, { name: "moonscript", remote: "leafo/moonscript-vim", }, { name: "nginx", remote: "chr4/nginx.vim", }, { name: "nim", remote: "zah/nim.vim", dirs: DIRS[:basic] }, { name: "nix", remote: "LnL7/vim-nix", }, { name: "objc", remote: "b4winckler/vim-objc", }, { name: "ocaml", remote: "rgrinberg/vim-ocaml", }, { name: "octave", remote: "McSinyx/vim-octave", }, { name: "opencl", remote: "petRUShka/vim-opencl", }, { name: "perl", remote: "vim-perl/vim-perl", }, { name: "pgsql", remote: "lifepillar/pgsql.vim", }, { name: "php", remote: "StanAngeloff/php.vim", }, { name: "plantuml", remote: "aklt/plantuml-syntax", }, { name: "pony", remote: "jakwings/vim-pony", }, { name: "powershell", remote: "PProvost/vim-ps1", }, { name: "protobuf", remote: "uarun/vim-protobuf", }, { name: "pug", remote: "digitaltoad/vim-pug", }, { name: "puppet", remote: "rodjek/vim-puppet", }, { name: "purescript", remote: "purescript-contrib/purescript-vim", }, { name: "python-compiler", remote: "aliev/vim-compiler-python", }, { name: "python-indent", remote: "Vimjas/vim-python-pep8-indent", }, { name: "python", remote: "vim-python/python-syntax", }, { name: "qmake", remote: "artoj/qmake-syntax-vim", }, { name: "qml", remote: "peterhoeg/vim-qml", }, { name: "r-lang", remote: "vim-scripts/R.vim", dirs: DIRS[:basic] }, { name: "racket", remote: "wlangstroth/vim-racket", }, { name: "ragel", remote: "jneen/ragel.vim", }, { name: "raku", remote: "Raku/vim-raku", }, { name: "raml", remote: "IN3D/vim-raml", }, { name: "razor", remote: "adamclerk/vim-razor", }, { name: "reason", remote: "reasonml-editor/vim-reason-plus", }, { name: "requirements", remote: "raimon49/requirements.txt.vim", }, { name: "rspec", remote: "keith/rspec.vim", }, { name: "rst", remote: "marshallward/vim-restructuredtext", }, { name: "ruby", remote: "vim-ruby/vim-ruby", }, { name: "rust", remote: "rust-lang/rust.vim", }, { name: "sbt", remote: "derekwyatt/vim-sbt", }, { name: "scala", remote: "derekwyatt/vim-scala", }, { name: "scss", remote: "cakebaker/scss-syntax.vim", }, { name: "sh", remote: "arzg/vim-sh", }, { name: "slim", remote: "slim-template/vim-slim", }, { name: "slime", remote: "slime-lang/vim-slime-syntax", }, { name: "smt2", remote: "bohlender/vim-smt2", }, { name: "solidity", remote: "tomlion/vim-solidity", }, { name: "sql", remote: "shmup/vim-sql-syntax", }, { name: "stylus", remote: "wavded/vim-stylus", }, { name: "svelte", remote: "evanleck/vim-svelte@main", }, { name: "svg-indent", remote: "jasonshell/vim-svg-indent", }, { name: "svg", remote: "vim-scripts/svg.vim", }, { name: "swift", remote: "keith/swift.vim", }, { name: "sxhkd", remote: "baskerville/vim-sxhkdrc", }, { name: "systemd", remote: "wgwoods/vim-systemd-syntax", }, { name: "terraform", remote: "hashivim/vim-terraform", }, { name: "textile", remote: "timcharper/textile.vim", }, { name: "thrift", remote: "solarnz/thrift.vim", }, { name: "tmux", remote: "ericpruitt/tmux.vim:vim", dirs: DIRS[:all] }, { name: "tomdoc", remote: "wellbredgrapefruit/tomdoc.vim", }, { name: "toml", remote: "cespare/vim-toml", }, { name: "tptp", remote: "c-cube/vim-tptp", }, { name: "twig", remote: "lumiliet/vim-twig", }, { name: "typescript", remote: "HerringtonDarkholme/yats.vim", }, { name: "unison", remote: "unisonweb/unison@trunk:editor-support/vim", dirs: DIRS[:all] }, { name: "v", remote: "ollykel/v-vim", }, { name: "vala", remote: "arrufat/vala.vim", }, { name: "vbnet", remote: "vim-scripts/vbnet.vim", }, { name: "vcl", remote: "smerrill/vcl-vim-plugin", }, { name: "vifm", remote: "vifm/vifm.vim", }, { name: "vm", remote: "lepture/vim-velocity", }, { name: "vue", remote: "posva/vim-vue", }, { name: "xdc", remote: "amal-khailtash/vim-xdc-syntax", }, { name: "xml", remote: "amadeus/vim-xml", }, { name: "xls", remote: "vim-scripts/XSLT-syntax", }, { name: "yaml", remote: "stephpy/vim-yaml", }, { name: "yard", remote: "sheerun/vim-yardoc", }, { name: "zephir", remote: "xwsoul/vim-zephir", }, { name: "zig", remote: "ziglang/zig.vim", }, { name: "zinit", remote: "zinit-zsh/zplugin-vim-syntax", } ] def parallel(*procs) threads = procs.map { |p| Thread.new { method(p).call } } threads.map(&:join).map(&:value) end def read_strings(data, keys, print=false) if data.is_a?(Hash) data.flat_map do |key, val| read_strings(val, keys, keys.include?(key)) end elsif data.is_a?(Array) data.flat_map { |d| read_strings(d, keys, print) } elsif data.is_a?(String) print ? [data] : [] else [] end end def transform_with(data, keys, transfrom=false, &block) if data.is_a?(Hash) Hash[data.map do |key, val| [key, transform_with(val, keys, keys.include?(key), &block)] end] elsif data.is_a?(Array) data.map { |d| transform_with(d, keys, transfrom, &block) } elsif data.is_a?(String) transfrom ? yield(data) : data else data end end def each_hash(data, &block) if data.is_a?(Hash) yield data data.each do |key, val| each_hash(val, &block) end elsif data.is_a?(Array) data.map { |d| each_hash(d, &block) } end end def patterns_to_vim_patterns(patterns) stdin, stdout, stderr = Open3.popen3('vim', '-V', '--clean', '/dev/stdin', '-es', '-c', "echo expand('%:p:h') | source #{__dir__}/eregex.vim", '-c', "for line in range(0, line('$')) | call setline(line, ExtendedRegex2VimRegex(getline(line))) | endfor", '-c', ':wq! /dev/stdout', chdir: __dir__) stdin.write(patterns.join("\n")) stdin.close stdout.readlines end def transform_patterns(data) patterns = read_strings(data, ["pattern", "patterns"]) patterns_mapping = Hash[patterns.zip(patterns_to_vim_patterns(patterns))] transform_with(data, ["pattern", "patterns"]) { |a| patterns_mapping[a] } end def load_heuristics url = "#{BASE_URL}/lib/linguist/heuristics.yml" data = URI.open(url) { |io| YAML.load(io.read) } each_hash(data["disambiguations"]) do |h| if h.has_key?("named_pattern") h["pattern"] = data["named_patterns"].fetch(h["named_pattern"]) h.delete("named_pattern") end end transform_patterns(data["disambiguations"]) end def load_languages url = "#{BASE_URL}/lib/linguist/languages.yml" data = URI.open(url) { |io| YAML.load(io.read) } end # heuristics, languages = parallel(:load_heuristics, :load_languages) def parse_remote(remote) match = remote.match(/(?[^@:]+)(?:@(?[^:]+))?(?::(?.*))?/) [match[:repo], match[:branch] || "master", match[:path]] end def copy_file(package, src, dest) return unless [".vim", ".ctags", ".vital"].include?(File.extname(src)) FileUtils.mkdir_p(File.dirname(dest)) open(src, "r") do |input| open(dest, "a+") do |output| if package[:name] == "jsx" output << "if !exists('g:polyglot_disabled') || !(index(g:polyglot_disabled, 'typescript') != -1 || index(g:polyglot_disabled, 'typescript') != -1 || index(g:polyglot_disabled, 'jsx') != -1)\n\n" else output << "if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, '#{package[:name]}') == -1\n\n" end IO.copy_stream(input, output) output << "\nendif\n" end end end def download FileUtils.rm_rf('tmp') PACKAGES.map do |package| Thread.new do repo, branch, path = parse_remote(package[:remote]) dir = "tmp/" + repo.split('/')[1] FileUtils.mkdir_p(dir) url = "https://codeload.github.com/#{repo}/tar.gz/#{branch}" `curl --silent -fL #{url} | tar -zx -C "#{dir}" --strip 1` progress end end.map(&:join) end $i = 0 LYRICS = "Never gonna give you up. Never gonna let you down. " + "Never gonna run around and desert you. " + "Never gonna make you cry. Never gonna say goodbye. " + "Never gonna tell a lie and hurt you." $mutex = Mutex.new def progress $mutex.synchronize do $stdout.write(LYRICS[$i] || ".") $i += 1 end end def extract FileUtils.rm_rf(DIRS[:all]) output = [] PACKAGES.map do |package| repo, branch, path = parse_remote(package[:remote]) dir = "tmp/" + repo.split('/')[1] subdirs = [] for subdir in package.fetch(:dirs, DIRS[:default]) subtree = "#{dir}/#{path ? path + "/" : ""}" subpath = "#{subtree}#{subdir}" if FileTest.directory?(subpath) Dir.glob("#{subdir}/**/*", base: subtree).each do |p| next unless File.file?("#{subtree}/#{p}") copy_file(package, "#{subtree}/#{p}", p) end subdirs << subdir.split("/").last elsif File.exist?(subpath) copy_file(package, subpath, subdir) end end output << "- [#{package[:name]}](https://github.com/#{repo}) (#{subdirs.uniq.join(", ")})" progress end readme = File.read('README.md') readme.gsub!( %r{(?<=).*?(?=)}, output.size.to_s ) readme.gsub!( %r{(?<=).*?(?=)}m, "\n" + output.sort.join("\n") + "\n" ) File.write('README.md', readme) end download extract puts(" Bye! Have a wonderful time!") FileUtils.rm_rf("tmp")