From d87fad649c32be985a6a009bf117ad26e7314daf Mon Sep 17 00:00:00 2001 From: chrisarcand Date: Sat, 16 Jan 2016 07:50:55 -0500 Subject: [PATCH] Improved vim modeline detection TLDR: This greatly increases the flexibility of vim modeline detection to manually set the language of a file. In vim there are two forms of modelines: [text]{white}{vi:|vim:|ex:}[white]{options} examples: 'vim: syntax=perl', 'ex: filetype=ruby' -and- [text]{white}{vi:|vim:|Vim:|ex:}[white]se[t] {options}:[text] examples: 'vim set syntax=perl:', 'Vim: se ft=ruby:' As you can see, there are many combinations. These changes should allow most combinations to be used. The two most important additions are the use of the keyword 'syntax', as well as the addition of the first form (you now no longer need to use the keyword 'set' with a colon at the end). The use of first form with 'syntax' is very, very common across GitHub: https://github.com/search?l=ruby&q=vim%3A+syntax%3D&ref=searchresults&type=Code&utf8=%E2%9C%93 --- README.md | 3 +++ lib/linguist/strategy/modeline.rb | 17 ++++++++++++++--- test/fixtures/Data/Modelines/ruby4 | 3 +++ test/fixtures/Data/Modelines/ruby5 | 3 +++ test/fixtures/Data/Modelines/ruby6 | 3 +++ test/fixtures/Data/Modelines/ruby7 | 3 +++ test/fixtures/Data/Modelines/ruby8 | 3 +++ test/fixtures/Data/Modelines/ruby9 | 3 +++ test/test_modelines.rb | 6 ++++++ 9 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 test/fixtures/Data/Modelines/ruby4 create mode 100644 test/fixtures/Data/Modelines/ruby5 create mode 100644 test/fixtures/Data/Modelines/ruby6 create mode 100644 test/fixtures/Data/Modelines/ruby7 create mode 100644 test/fixtures/Data/Modelines/ruby8 create mode 100644 test/fixtures/Data/Modelines/ruby9 diff --git a/README.md b/README.md index 36bcbd50..2d661ef9 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,9 @@ Alternatively, you can use Vim or Emacs style modelines to set the language for ##### Vim ``` +# Some examples of various styles: +vim: syntax=java +vim: set syntax=ruby: vim: set filetype=prolog: vim: set ft=cpp: ``` diff --git a/lib/linguist/strategy/modeline.rb b/lib/linguist/strategy/modeline.rb index f995d940..ece98a1f 100644 --- a/lib/linguist/strategy/modeline.rb +++ b/lib/linguist/strategy/modeline.rb @@ -1,8 +1,19 @@ module Linguist module Strategy class Modeline - EmacsModeline = /-\*-\s*(?:(?!mode)[\w-]+\s*:\s*(?:[\w+-]+)\s*;?\s*)*(?:mode\s*:)?\s*([\w+-]+)\s*(?:;\s*(?!mode)[\w-]+\s*:\s*[\w+-]+\s*)*;?\s*-\*-/i - VimModeline = /vim:\s*set.*\s(?:ft|filetype)=(\w+)\s?.*:/i + EMACS_MODELINE = /-\*-\s*(?:(?!mode)[\w-]+\s*:\s*(?:[\w+-]+)\s*;?\s*)*(?:mode\s*:)?\s*([\w+-]+)\s*(?:;\s*(?!mode)[\w-]+\s*:\s*[\w+-]+\s*)*;?\s*-\*-/i + + # First form vim modeline + # [text]{white}{vi:|vim:|ex:}[white]{options} + # ex: 'vim: syntax=perl' + VIM_MODELINE_1 = /(?:vim|vi|ex):\s*(?:ft|filetype|syntax)=(\w+)\s?/i + + # Second form vim modeline (compatible with some versions of Vi) + # [text]{white}{vi:|vim:|Vim:|ex:}[white]se[t] {options}:[text] + # ex: 'vim set syntax=perl:' + VIM_MODELINE_2 = /(?:vim|vi|Vim|ex):\s*se(?:t)?.*\s(?:ft|filetype|syntax)=(\w+)\s?.*:/i + + MODELINES = [EMACS_MODELINE, VIM_MODELINE_1, VIM_MODELINE_2] # Public: Detects language based on Vim and Emacs modelines # @@ -22,7 +33,7 @@ module Linguist # # Returns a String or nil def self.modeline(data) - match = data.match(EmacsModeline) || data.match(VimModeline) + match = MODELINES.map { |regex| data.match(regex) }.reject(&:nil?).first match[1] if match end end diff --git a/test/fixtures/Data/Modelines/ruby4 b/test/fixtures/Data/Modelines/ruby4 new file mode 100644 index 00000000..e3b50151 --- /dev/null +++ b/test/fixtures/Data/Modelines/ruby4 @@ -0,0 +1,3 @@ +# vim: filetype=ruby + +# I am Ruby diff --git a/test/fixtures/Data/Modelines/ruby5 b/test/fixtures/Data/Modelines/ruby5 new file mode 100644 index 00000000..10349050 --- /dev/null +++ b/test/fixtures/Data/Modelines/ruby5 @@ -0,0 +1,3 @@ +# vim: ft=ruby + +# I am Ruby diff --git a/test/fixtures/Data/Modelines/ruby6 b/test/fixtures/Data/Modelines/ruby6 new file mode 100644 index 00000000..a2b49dae --- /dev/null +++ b/test/fixtures/Data/Modelines/ruby6 @@ -0,0 +1,3 @@ +# vim: syntax=Ruby + +# I am Ruby diff --git a/test/fixtures/Data/Modelines/ruby7 b/test/fixtures/Data/Modelines/ruby7 new file mode 100644 index 00000000..1ed5b28f --- /dev/null +++ b/test/fixtures/Data/Modelines/ruby7 @@ -0,0 +1,3 @@ +# vim: se syntax=ruby: + +# I am Ruby diff --git a/test/fixtures/Data/Modelines/ruby8 b/test/fixtures/Data/Modelines/ruby8 new file mode 100644 index 00000000..8e854741 --- /dev/null +++ b/test/fixtures/Data/Modelines/ruby8 @@ -0,0 +1,3 @@ +# vim: set syntax=ruby: + +# I am Ruby diff --git a/test/fixtures/Data/Modelines/ruby9 b/test/fixtures/Data/Modelines/ruby9 new file mode 100644 index 00000000..ac82358d --- /dev/null +++ b/test/fixtures/Data/Modelines/ruby9 @@ -0,0 +1,3 @@ +# ex: syntax=ruby + +# I am Ruby diff --git a/test/test_modelines.rb b/test/test_modelines.rb index fd259782..85718955 100644 --- a/test/test_modelines.rb +++ b/test/test_modelines.rb @@ -11,6 +11,12 @@ class TestModelines < Minitest::Test assert_modeline Language["Ruby"], fixture_blob("Data/Modelines/ruby") assert_modeline Language["Ruby"], fixture_blob("Data/Modelines/ruby2") assert_modeline Language["Ruby"], fixture_blob("Data/Modelines/ruby3") + assert_modeline Language["Ruby"], fixture_blob("Data/Modelines/ruby4") + assert_modeline Language["Ruby"], fixture_blob("Data/Modelines/ruby5") + assert_modeline Language["Ruby"], fixture_blob("Data/Modelines/ruby6") + assert_modeline Language["Ruby"], fixture_blob("Data/Modelines/ruby7") + assert_modeline Language["Ruby"], fixture_blob("Data/Modelines/ruby8") + assert_modeline Language["Ruby"], fixture_blob("Data/Modelines/ruby9") assert_modeline Language["C++"], fixture_blob("Data/Modelines/seeplusplus") assert_modeline Language["C++"], fixture_blob("Data/Modelines/seeplusplusEmacs1") assert_modeline Language["C++"], fixture_blob("Data/Modelines/seeplusplusEmacs2")