diff --git a/fzf b/fzf
index c210cd8e19264badbc064435ad5d71ce25693c5b..8f29d5bd595aa651bbccf72e4d31a483fbb1290c 100755
--- a/fzf
+++ b/fzf
@@ -110,7 +110,7 @@ when /darwin/
       ret
     end
 
-    def self.nfc str, b = 0, e = 0
+    def self.nfc str, offsets = []
       ret  = ''
       omap = []
       pend = []
@@ -138,7 +138,10 @@ when /darwin/
           ret << c
         end
       end
-      return [ret, omap[b] || 0, omap[e] || ((omap.last || 0) + 1)]
+      return [ret,
+              offsets.map { |pair|
+                b, e = pair
+                [omap[b] || 0, omap[e] || ((omap.last || 0) + 1)] }]
     end
   end
 
@@ -212,6 +215,69 @@ def ctrl char
   char.to_s.ord - 'a'.ord + 1
 end
 
+def format line, limit, offsets
+  offsets ||= []
+  maxe = offsets.map { |e| e.last }.max || 0
+
+  # Overflow
+  if width(line) > limit
+    ewidth = width(line[0...maxe])
+    # Stri..
+    if ewidth <= limit - 2
+      line, _ = trim line, limit - 2, false
+      line << '..'
+    # ..ring
+    else
+      # ..ri..
+      line = line[0...maxe] + '..' if ewidth < width(line) - 2
+      line, diff = trim line, limit - 2, true
+      offsets = offsets.map { |pair|
+        b, e = pair
+        b += 2 - diff
+        e += 2 - diff
+        b = [2, b].max
+        [b, e]
+      }
+      line = '..' + line
+    end
+  end
+
+  tokens = []
+  index = 0
+  offsets.select  { |pair| pair.first < pair.last }.
+          sort_by { |pair| pair }.each do |pair|
+    b, e = pair.map { |x| [index, x].max }
+    tokens << [line[index...b], false]
+    tokens << [line[b...e], true]
+    index = e
+  end
+  tokens << [line[index..-1], false]
+  tokens.reject { |pair| pair.first.empty? }
+end
+
+def print_item row, tokens, chosen, selected
+  # Cursor
+  C.setpos row, 0
+  C.clrtoeol
+  cprint chosen ? '>' : ' ', color(:red, true)
+  cprint selected ? '>' : ' ',
+    chosen ? color(:chosen) : (selected ? color(:red, true) : 0)
+
+  # Highlighted item
+  C.attron color(:chosen, true) if chosen
+  tokens.each do |pair|
+    token, highlighted = pair
+
+    if highlighted
+      cprint   token, color(chosen ? :match! : :match, chosen)
+      C.attron color(:chosen, true) if chosen
+    else
+      C.addstr token
+    end
+  end
+  C.attroff color(:chosen, true) if chosen
+end
+
 if RUBY_VERSION.split('.').map { |e| e.rjust(3, '0') }.join > '001009'
   @wrx = Regexp.new '\p{Han}|\p{Katakana}|\p{Hiragana}|\p{Hangul}'
   def width str
@@ -421,7 +487,7 @@ searcher = Thread.new {
                 (partial_cache ? partial_cache.map { |e| e.first } : list).map { |line|
                   # Ignore errors: e.g. invalid byte sequence in UTF-8
                   md = line.match(regexp) rescue nil
-                  md && [line, *md.offset(0)]
+                  md && [line, [md.offset(0)]]
                 }.compact
               end)
             end
@@ -431,9 +497,11 @@ searcher = Thread.new {
 
         mcount = matches.length
         if @sort && mcount <= @sort && !q.empty?
-          matches.replace matches.sort_by { |triple|
-            line, b, e = triple
-            [b ? (e - b) : 0, line.length, line]
+          matches.replace matches.sort_by { |tuple|
+            line, offsets = tuple
+            matchlen = offsets.map { |pair| pair.last }.max || 0 -
+                       offsets.map { |pair| pair.first }.min || 0
+            [matchlen, line.length, line]
           }
         end
       end#new_search
@@ -462,50 +530,12 @@ searcher = Thread.new {
         maxc = C.cols - 3
         matches[0, max_items].each_with_index do |item, idx|
           next if !new_search && !((vcursor-1)..(vcursor+1)).include?(idx)
-
-          line, b, e = convert_item item
-          b ||= 0
-          e ||= 0
           row = cursor_y - idx - 2
           chosen = idx == vcursor
-
-          # Overflow
-          if width(line) > maxc
-            ewidth = width(line[0...e])
-            # Stri..
-            if ewidth <= maxc - 2
-              line, _ = trim line, maxc - 2, false
-              line << '..'
-            # ..ring
-            else
-              # ..ri..
-              line = line[0...e] + '..' if ewidth < width(line) - 2
-              line, diff = trim line, maxc - 2, true
-              b += 2 - diff
-              e += 2 - diff
-              b = [2, b].max
-              line = '..' + line
-            end
-          end
-
-          C.setpos row, 0
-          C.clrtoeol
-          cprint chosen ? '>' : ' ', color(:red, true)
           selected = selects.include?([*item][0])
-          cprint selected ? '>' : ' ',
-            chosen ? color(:chosen) : (selected ? color(:red, true) : 0)
-
-          C.attron color(:chosen, true) if chosen
-
-          if b < e
-            C.addstr line[0, b]
-            cprint   line[b...e], color(chosen ? :match! : :match, chosen)
-            C.attron color(:chosen, true) if chosen
-            C.addstr line[e..-1] || ''
-          else
-            C.addstr line
-          end
-          C.attroff color(:chosen, true) if chosen
+          line, offsets = convert_item item
+          tokens = format line, maxc, offsets
+          print_item row, tokens, chosen, selected
         end
 
         print_info selects.length if !@lists.empty? || events[:loaded]