@@ -25,16 +25,15 @@ def setup(app):
25
25
rev = get_github_rev ()
26
26
27
27
# links to files or folders on the GitHub
28
- baseurl = 'https://github.com/espressif/esp-idf'
29
- app .add_role ('idf' , autolink ('{}/tree/{}/%s' .format (baseurl , rev )))
30
- app .add_role ('idf_file' , autolink ('{}/blob/{}/%s' .format (baseurl , rev )))
31
- app .add_role ('idf_raw' , autolink ('{}/raw/{}/%s' .format (baseurl , rev )))
32
- app .add_role ('component' , autolink ('{}/tree/{}/components/%s' .format (baseurl , rev )))
33
- app .add_role ('component_file' , autolink ('{}/blob/{}/components/%s' .format (baseurl , rev )))
34
- app .add_role ('component_raw' , autolink ('{}/raw/{}/components/%s' .format (baseurl , rev )))
35
- app .add_role ('example' , autolink ('{}/tree/{}/examples/%s' .format (baseurl , rev )))
36
- app .add_role ('example_file' , autolink ('{}/blob/{}/examples/%s' .format (baseurl , rev )))
37
- app .add_role ('example_raw' , autolink ('{}/raw/{}/examples/%s' .format (baseurl , rev )))
28
+ app .add_role ('idf' , github_link ('tree' , rev , '/' , app .config ))
29
+ app .add_role ('idf_file' , github_link ('blob' , rev , '/' , app .config ))
30
+ app .add_role ('idf_raw' , github_link ('raw' , rev , '/' , app .config ))
31
+ app .add_role ('component' , github_link ('tree' , rev , '/components/' , app .config ))
32
+ app .add_role ('component_file' , github_link ('blob' , rev , '/components/' , app .config ))
33
+ app .add_role ('component_raw' , github_link ('raw' , rev , '/components/' , app .config ))
34
+ app .add_role ('example' , github_link ('tree' , rev , '/examples/' , app .config ))
35
+ app .add_role ('example_file' , github_link ('blob' , rev , '/examples/' , app .config ))
36
+ app .add_role ('example_raw' , github_link ('raw' , rev , '/examples/' , app .config ))
38
37
39
38
# link to the current documentation file in specific language version
40
39
on_rtd = os .environ .get ('READTHEDOCS' , None ) == 'True'
@@ -49,21 +48,72 @@ def setup(app):
49
48
50
49
app .add_role ('link_to_translation' , crosslink ('%s../../%s/{}/%s.html' .format (tag_rev )))
51
50
52
- return {'parallel_read_safe' : True , 'parallel_write_safe' : True , 'version' : '0.1 ' }
51
+ return {'parallel_read_safe' : True , 'parallel_write_safe' : True , 'version' : '0.2 ' }
53
52
54
53
55
- def autolink ( pattern ):
54
+ def github_link ( link_type , rev , root_path , app_config ):
56
55
def role (name , rawtext , text , lineno , inliner , options = {}, content = []):
57
- m = re .search ('(.*)\s*<(.*)>' , text ) # noqa: W605 - regular expression
56
+ msgs = []
57
+
58
+ def warning (msg ):
59
+ system_msg = inliner .reporter .warning (msg )
60
+ system_msg .line = lineno
61
+ msgs .append (system_msg )
62
+
63
+ BASE_URL = 'https://github.com/espressif/esp-idf'
64
+
65
+ # search for a named link (:label<path>) with descriptive label vs a plain URL
66
+ m = re .search (r'(.*)\s*<(.*)>' , text )
58
67
if m :
59
68
link_text = m .group (1 )
60
69
link = m .group (2 )
61
70
else :
62
71
link_text = text
63
72
link = text
64
- url = pattern % (link ,)
73
+
74
+ rel_path = root_path + link
75
+ abs_path = os .path .join (app_config .idf_path , rel_path .lstrip ('/' ))
76
+ line_no = None
77
+ url = BASE_URL + link_type + rel_path
78
+
79
+ if '#L' in abs_path :
80
+ # drop any URL line number from the file, line numbers take the form #Lnnn or #Lnnn-Lnnn for a range
81
+ abs_path , line_no = abs_path .split ('#L' )
82
+ line_no = re .search (r'^(\d+)(?:-L(\d+))?' , line_no )
83
+ if line_no is None :
84
+ warning ("Line number anchor in URL %s doesn't seem to be valid" % link )
85
+ else :
86
+ line_no = tuple (int (l ) for l in line_no .groups () if l ) # tuple of (nnn,) or (nnn, NNN) for ranges
87
+ elif '#' in abs_path : # drop any other anchor from the line
88
+ abs_path = abs_path .split ('#' )[0 ]
89
+ warning ("URL %s seems to contain an unusable anchor after the #, only line numbers are supported" % link )
90
+
91
+ is_dir = (link_type == 'tree' )
92
+
93
+ if not os .path .exists (abs_path ):
94
+ warning ("IDF path %s does not appear to exist (absolute path %s)" % (rel_path , abs_path ))
95
+ elif is_dir and not os .path .isdir (abs_path ):
96
+ # note these "wrong type" warnings are not strictly needed as GitHub will apply a redirect,
97
+ # but the may become important in the future (plus make for cleaner links)
98
+ warning ("IDF path %s is not a directory but role :%s: is for linking to a directory, try :%s_file:" % (rel_path , name , name ))
99
+ elif not is_dir and os .path .isdir (abs_path ):
100
+ warning ("IDF path %s is a directory but role :%s: is for linking to a file" % (rel_path , name ))
101
+
102
+ # check the line number is valid
103
+ if line_no :
104
+ if is_dir :
105
+ warning ("URL %s contains a line number anchor but role :%s: is for linking to a directory" % (rel_path , name , name ))
106
+ elif os .path .exists (abs_path ) and not os .path .isdir (abs_path ):
107
+ with open (abs_path , "r" ) as f :
108
+ lines = len (f .readlines ())
109
+ if any (True for l in line_no if l > lines ):
110
+ warning ("URL %s specifies a range larger than file (file has %d lines)" % (rel_path , lines ))
111
+
112
+ if tuple (sorted (line_no )) != line_no : # second line number comes before first one!
113
+ warning ("URL %s specifies a backwards line number range" % rel_path )
114
+
65
115
node = nodes .reference (rawtext , link_text , refuri = url , ** options )
66
- return [node ], []
116
+ return [node ], msgs
67
117
return role
68
118
69
119
0 commit comments