|
#! /usr/bin/env python |
|
# -*- coding: utf-8 -*- |
|
|
|
from __future__ import print_function |
|
|
|
help_text = """ |
|
Extracts tags from rmd files. Useful for the Tagbar plugin. |
|
|
|
Usage: |
|
Install Tagbar (http://majutsushi.github.io/tagbar/). Then, put this file |
|
anywhere and add the following to your .vimrc: |
|
|
|
let g:tagbar_type_rmd = { |
|
\ 'ctagstype':'rmd' |
|
\ , 'kinds':['h:header', 'c:chunk', 'f:function', 'v:variable'] |
|
\ , 'sro':'&&&' |
|
\ , 'kind2scope':{'h':'header', 'c':'chunk', 'f':'function', 'v':'variable'} |
|
\ , 'sort':0 |
|
\ , 'ctagsbin':'/path/to/rmdtags.py' |
|
\ . 'ctagsargs':'' |
|
\ } |
|
""" |
|
|
|
import sys |
|
import re |
|
|
|
if len(sys.argv) < 2: |
|
print(help_text) |
|
exit() |
|
|
|
filename = sys.argv[1] |
|
|
|
# filename = "test.Rmd" |
|
print(filename) |
|
|
|
re_header = re.compile(r"^(#+)([^{]+)(\{[^}]+\})?$") |
|
re_chunk = re.compile(r"^```\{r ([^,]+)(,[^}]*)?\}$") |
|
re_function = re.compile(r"^[\t ]*([^ ]+) *<- *function.*$") |
|
re_variable1 = re.compile(r"^[\t ]*([^ ]+) *<-.*$") |
|
re_variable2 = re.compile(r"^.*-> *(.+)$") |
|
|
|
file_content = [] |
|
try: |
|
with open(filename, "r") as vim_buffer: |
|
file_content = vim_buffer.readlines() |
|
except: |
|
exit() |
|
|
|
headers = [] |
|
depth = [0] |
|
inChunk = False |
|
curChunk = None |
|
for lnum, line in enumerate(file_content): |
|
newline = [] |
|
tag = "" |
|
signature = "" |
|
options = "" |
|
# Headers |
|
if re_header.match(line) and not inChunk: |
|
level = len(re_header.match(line).group(1)) |
|
tag = re_header.match(line).group(2).strip() |
|
newline.append(tag) |
|
newline.append(filename) |
|
newline.append('/^' + line.rstrip("\n") + '$/;"') |
|
newline.append("h") |
|
newline.append("line:" + str(lnum+1)) |
|
# header |
|
while (level <= depth[len(depth) -1]): |
|
headers.pop() |
|
depth.pop() |
|
if len(headers) > 0: |
|
options = "header:" + "&&&".join(headers) |
|
headers.append(tag) |
|
depth.append(level) |
|
# signature |
|
if re_header.match(line).group(3): |
|
signature = "(" + re_header.match(line).group(3).strip("{}") + ")" |
|
options = options + "\tsignature:" + signature |
|
# Print |
|
newline.append(options) |
|
print("\t".join(newline)) |
|
# Chunks |
|
if re_chunk.match(line): |
|
inChunk = True |
|
curChunk = re_chunk.match(line).group(1).strip() |
|
newline.append(re_chunk.match(line).group(1).strip()) |
|
newline.append(filename) |
|
newline.append('/^' + line.rstrip("\n") + '$/;"') |
|
newline.append("c") |
|
newline.append("line:" + str(lnum+1)) |
|
if len(headers) > 0: |
|
options = "header:" + "&&&".join(headers) |
|
if re_chunk.match(line).group(2): |
|
signature = "(" + re_chunk.match(line).group(2).lstrip(", ") + ")" |
|
options = options + "\tsignature:" + signature |
|
# Print |
|
newline.append(options) |
|
print("\t".join(newline)) |
|
if line == "```\n": |
|
inChunk = False |
|
curChunk = None |
|
# Functions |
|
if re_function.match(line) and inChunk: |
|
newline.append(re_function.match(line).group(1).strip()) |
|
newline.append(filename) |
|
newline.append('/^' + line.rstrip("\n") + '$/;"') |
|
newline.append("f") |
|
newline.append("line:" + str(lnum+1)) |
|
print("\t".join(newline)) |
|
elif (re_variable1.match(line) or re_variable2.match(line)) and inChunk: |
|
tag = re_variable1.match(line) or re_variable2.match(line) |
|
tag = tag.group(1).strip() |
|
newline.append(tag) |
|
newline.append(filename) |
|
newline.append('/^' + line.rstrip("\n") + '$/;"') |
|
newline.append("v") |
|
newline.append("line:" + str(lnum+1)) |
|
print("\t".join(newline)) |
|
|
Hi Maxime, thanks for this tag generator. I found this gist through your blog. I've been using your script for the past 6 months, maybe. I would like to expand the list of tags and include inline chunks that are located in the main text as:
I think the variable for finding inline chunks could be (but I may be wrong):
But I have no idea how to allocate it in your code. Any idea? Thanks again!