Update runtime files.
diff --git a/runtime/indent/sas.vim b/runtime/indent/sas.vim
new file mode 100644
index 0000000..d591b27
--- /dev/null
+++ b/runtime/indent/sas.vim
@@ -0,0 +1,138 @@
+" Vim indent file
+" Language:     SAS
+" Maintainer:   Zhen-Huan Hu <wildkeny@gmail.com>
+" Version:      3.0.1
+" Last Change:  Mar 13, 2017
+
+if exists("b:did_indent")
+  finish
+endif
+let b:did_indent = 1
+
+setlocal indentexpr=GetSASIndent()
+setlocal indentkeys+=;,=~data,=~proc,=~macro
+
+if exists("*GetSASIndent")
+  finish
+endif
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+" Regex that captures the start of a data/proc section
+let s:section_str = '\v%(^|;)\s*%(data|proc)>'
+" Regex that captures the end of a run-processing section
+let s:section_run = '\v%(^|;)\s*run\s*;'
+" Regex that captures the end of a data/proc section
+let s:section_end = '\v%(^|;)\s*%(quit|enddata)\s*;'
+
+" Regex that captures the start of a control block (anything inside a section)
+let s:block_str = '\v<%(do>%([^;]+<%(to|over)>[^;]+)=|%(define|layout|method|select)>[^;]+|begingraph)\s*;'
+" Regex that captures the end of a control block (anything inside a section)
+let s:block_end = '\v<%(end|endlayout|endgraph)\s*;'
+
+" Regex that captures the start of a macro
+let s:macro_str = '\v%(^|;)\s*\%macro>'
+" Regex that captures the end of a macro
+let s:macro_end = '\v%(^|;)\s*\%mend\s*;'
+
+" Regex that defines the end of the program
+let s:program_end = '\v%(^|;)\s*endsas\s*;'
+
+" List of procs supporting run-processing
+let s:run_processing_procs = [
+      \ 'catalog', 'chart', 'datasets', 'document', 'ds2', 'plot', 'sql',
+      \ 'gareabar', 'gbarline', 'gchart', 'gkpi', 'gmap', 'gplot', 'gradar', 'greplay', 'gslide', 'gtile',
+      \ 'anova', 'arima', 'catmod', 'factex', 'glm', 'model', 'optex', 'plan', 'reg',
+      \ 'iml',
+      \ ]
+
+" Find the line number of previous keyword defined by the regex
+function! s:PrevMatch(lnum, regex)
+  let prev_lnum = prevnonblank(a:lnum - 1)
+  while prev_lnum > 0
+    let prev_line = getline(prev_lnum)
+    if prev_line =~ a:regex
+      break
+    else
+      let prev_lnum = prevnonblank(prev_lnum - 1)
+    endif
+  endwhile
+  return prev_lnum
+endfunction
+
+" Main function
+function! GetSASIndent()
+  let prev_lnum = prevnonblank(v:lnum - 1)
+  if prev_lnum ==# 0
+    " Leave the indentation of the first line unchanged
+    return indent(1)
+  else
+    let prev_line = getline(prev_lnum)
+    " Previous non-blank line contains the start of a macro/section/block
+    " while not the end of a macro/section/block (at the same line)
+    if (prev_line =~ s:section_str && prev_line !~ s:section_run && prev_line !~ s:section_end) ||
+          \ (prev_line =~ s:block_str && prev_line !~ s:block_end) ||
+          \ (prev_line =~ s:macro_str && prev_line !~ s:macro_end)
+      let ind = indent(prev_lnum) + &sts
+    elseif prev_line =~ s:section_run && prev_line !~ s:section_end
+      let prev_section_str_lnum = s:PrevMatch(v:lnum, s:section_str)
+      let prev_section_end_lnum = max([
+            \ s:PrevMatch(v:lnum, s:section_end),
+            \ s:PrevMatch(v:lnum, s:macro_end  ),
+            \ s:PrevMatch(v:lnum, s:program_end)])
+      " Check if the section supports run-processing
+      if prev_section_end_lnum < prev_section_str_lnum &&
+            \ getline(prev_section_str_lnum) =~ '\v%(^|;)\s*proc\s+%(' .
+            \ join(s:run_processing_procs, '|') . ')>'
+        let ind = indent(prev_lnum) + &sts
+      else
+        let ind = indent(prev_lnum)
+      endif
+    else
+      let ind = indent(prev_lnum)
+    endif
+  endif
+  " Re-adjustments based on the inputs of the current line
+  let curr_line = getline(v:lnum)
+  if curr_line =~ s:program_end
+    " End of the program
+    " Same indentation as the first non-blank line
+    return indent(nextnonblank(1))
+  elseif curr_line =~ s:macro_end
+    " Current line is the end of a macro
+    " Match the indentation of the start of the macro
+    return indent(s:PrevMatch(v:lnum, s:macro_str))
+  elseif curr_line =~ s:block_end && curr_line !~ s:block_str
+    " Re-adjust if current line is the end of a block
+    " while not the beginning of a block (at the same line)
+    " Returning the indent of previous block start directly
+    " would not work due to nesting
+    let ind = ind - &sts
+  elseif curr_line =~ s:section_str || curr_line =~ s:section_run || curr_line =~ s:section_end
+    " Re-adjust if current line is the start/end of a section
+    " since the end of a section could be inexplicit
+    let prev_section_str_lnum = s:PrevMatch(v:lnum, s:section_str)
+    " Check if the previous section supports run-processing
+    if getline(prev_section_str_lnum) =~ '\v%(^|;)\s*proc\s+%(' .
+          \ join(s:run_processing_procs, '|') . ')>'
+      let prev_section_end_lnum = max([
+            \ s:PrevMatch(v:lnum, s:section_end),
+            \ s:PrevMatch(v:lnum, s:macro_end  ),
+            \ s:PrevMatch(v:lnum, s:program_end)])
+    else
+      let prev_section_end_lnum = max([
+            \ s:PrevMatch(v:lnum, s:section_end),
+            \ s:PrevMatch(v:lnum, s:section_run),
+            \ s:PrevMatch(v:lnum, s:macro_end  ),
+            \ s:PrevMatch(v:lnum, s:program_end)])
+    endif
+    if prev_section_end_lnum < prev_section_str_lnum
+      let ind = ind - &sts
+    endif
+  endif
+  return ind
+endfunction
+
+let &cpo = s:cpo_save
+unlet s:cpo_save