print("DEPRECATED") if __name__ == "__main__": import sys sys.path.append("../kutil") sys.path.append("../target") import re import klammer_base import kutil import html_util from html_util import E import latex_util as L import pprint import phases def escape_newlines(s): return re.sub("\n", " ___NL___ ", s) # def literal_newline(s): # def replace(match): # before, after = match.groups() # return f"{before}\\n{after}" # backslash_pat = re.compile(r'(".*?)\n(.*?")', re.S) # return backslash_pat.sub(replace, s) def is_comment(s): return s.strip().startswith("//") def split_blocks(s): print('-'*40) print(s) print('-'*40) blocks = [] in_code = True block = "" for line in s.rstrip().split("\n"): if is_comment(line): if in_code: blocks.append(block) block = line + "\n" in_code = False else: block += line + "\n" else: if not in_code: blocks.append(block) block = line + "\n" in_code = True else: block += line + "\n" if block: blocks.append(block) for block in blocks: print("B:") print(block) return blocks def parse_blocks(blocks): box_comment_rgx = re.compile("\s*//(\d+)\s+.*", re.S) i = 0 while i < len(blocks): match = box_comment_rgx.match(blocks[i]) if match: print(match.group(1)) i += 1 def get_blocks(s): comment_pat = re.compile(r"(\s*)//(\d+)\s+(.*)", re.S) blocks = [] lines = s.strip("\n").split("\n") i = 0 uncommented = "" while i < len(lines): match = comment_pat.match(lines[i]) if match: if uncommented: blocks.append([uncommented.rstrip(), None]) uncommented = "" count = int(match.group(2)) comment = match.group(3) code = "" j = 0 i += 1 while j < count: line = re.sub("\n", "\\n", lines[i]) code += line + "\n" j += 1 i += 1 blocks.append([code.strip("\n"), comment]) else: uncommented += lines[i] + "\n" i += 1 if uncommented: blocks.append([uncommented.rstrip(), None]) return blocks def latex_spaces(s): def replace(match): s = match.group(0) if False and len(s) == 1: return "~" else: result = "~" * len(s) result = f"\\hphantom{{{result}}}" return result space_pat = re.compile(" +", re.S) return space_pat.sub(replace, s) def latex_unquote(s): quoted = "asciicircum quotesingle asciigrave asciitilde asciitilde backslash".split() quoted = [f"{{}}\text{e}{{}}" for e in quoted] result = s for q in quoted: result = re.sub(q, "X", result) result = re.sub(" ", "Y", result) return result def longest_line(s): result = "" for line in latex_unquote(s).split("\n"): if len(line) > len(result): result = line return result def literal_newline(s): def replace(match): before, after = match.groups() return f"{before}\\n{after}" backslash_pat = re.compile(r'(".*?)\n(.*?")', re.S) return backslash_pat.sub(replace, s) class Code(klammer_base.Klammer_base): id = 0 def __init__(self, K): super().__init__(K) self.text = phases.expand_whitespace_markers(self.text) def html(self): if self.K_target == "html": self.text = literal_newline(self.text) # Escape Klammertext special characters so they survive # re-insertion into the katom stream after @eval self.text = self.text.replace("^", "^^") self.text = self.text.replace("#", "^#") self.text = self.text.replace("@", "^@") self.text = self.text.replace("|", "^|") self.blocks = get_blocks(self.text) result = '' for text, comment in self.blocks: border = "code_border" if comment else "code_no_border" body = E("div").body(text).cls(f"code_text {border}").str(None) if comment: body += "\n" + E("div").body(comment).cls("code_comment").str() result += E("div").body(body).cls("code_block").str() if self.number or self.caption: #result = html_util.add_caption( # result, "Listing", self.number, self.caption, "i", "left", "top") caption = kutil.caption_marker("Listing", self.caption) result = f'
{caption}
{result}\n' return result @staticmethod def escape_latex(s): """Escape LaTeX special characters in code text.""" # Backslash must be first (before adding more backslashes) s = s.replace("\\", "\\textbackslash{}") s = s.replace("{", "\\{") s = s.replace("}", "\\}") s = s.replace("%", "\\%") s = s.replace("$", "\\$") s = s.replace("&", "\\&") s = s.replace("_", "\\_") s = s.replace("^", "\\textasciicircum{}") s = s.replace("~", "\\textasciitilde{}") s = s.replace("<", "\\textless{}") s = s.replace(">", "\\textgreater{}") return s def code_box(self, text): kutil.msg(text) result = "" for line in text.rstrip().split("\n"): indent = len(line) - len(line.lstrip()) eline = ("~" * indent) + line[indent:] print(indent, line) print(eline) result += eline + "\\\\\n" result = result[:-3] print("RESULT:") print(result) return result def tex(self): parse_blocks(split_blocks(self.text)) return "" # Escape Klammertext special characters self.text = self.text.replace("^", "^^") self.text = self.text.replace("#", "^#") self.text = self.text.replace("@", "^@") self.text = self.text.replace("|", "^|") # Escape LaTeX special characters in code text self.text = Code.escape_latex(self.text) self.blocks = get_blocks(self.text) strutvis = "0pt" start_strut = f"\\rule[0pt]{{{strutvis}}}{{12pt}}" end_strut = f"\\rule[-6pt]{{{strutvis}}}{{12pt}}" caption_strut = f"\\rule[-8pt]{{{strutvis}}}{{6pt}}" indent = "8pt" comment_sep = "10pt" i = 0 result = "" count = len(self.blocks) for text, comment in self.blocks: print("TEXT:") print(text) print("COMMENT:") print(comment) text = " " + re.sub("\n", " \n ", text) + " " longest = longest_line(text) text = latex_spaces(text) text = re.sub("\n", r"\\\\", text) text = f"{start_strut}\\ttfamily {text}{end_strut}" width = f"\\widthof{{\\ttfamily {longest}}}" code = L.environment("minipage", text, width) + "\\\\\n" print(code) #code = "\\asymbox{" + self.code_box(text) + "}" #print(code) code = text if comment: #width = f"\\linewidth - {width} - {indent} - {comment_sep}" """ width = f"\\linewidth - \widestline - {indent} - {comment_sep}" code = f"\\fcolorbox{{Gray}}{{LightGray}}{{{code}}}" code += f"\\rule{{{comment_sep}}}{{{strutvis}}}" \ + L.environment("minipage", "\\sffamily\\small\\raggedright " + comment, width) """ code = "\\asymbox{" + self.code_box(text) + "}" + comment result += f"\\rule{{{indent}}}{{{strutvis}}}{code}" if comment: if i < count - 1 and self.blocks[i+1][1]: result += "\\\\[4pt]" i += 1 if not self.blocks[count-1][1]: result = result[:-4] if self.number or self.caption: caption = kutil.caption_marker("Listing", self.caption) if self.blocks[0][1]: caption += caption_strut strut = f"\\rule{{{indent}}}{{{strutvis}}}" result = f"{strut}\\emph{{\\it {caption}}}\\newline\n" + result + "\n" result = f"\\hypertarget{{Reference-Listing-{Code.id}}}{{}}\n{result}" Code.id += 1 return result def undash(s): result = s result = re.sub("__MDASH__", "---", result) result = re.sub("__NDASH__", "--", result) return result class Code_fragment(klammer_base.Klammer_base): def __init__(self, K): super().__init__(K) def html(self): #print(f"code: |{self.code_text}|") result = self.code_text.strip() result = undash(result) #result = re.escape(result) result = re.sub("<", "<", result) result = re.sub(" ", " ", result) #print(f"code: |{self.code_text}| -> |{result}|") return f'{result}' def tex(self): return f"{{\\tt {self.code_text.strip()}}}" def show(s): print("-"*80) print(s) print("-"*80) class Source(klammer_base.Klammer_base): def __init__(self, K): super().__init__(K) with open(self.filename) as fp: self.src = fp.read() def tex(self): result = self.src # result = re.sub("#", "^#", result) # result = re.sub("\\^", "\\^", result) result = f"\\begin{{verbatim}}\n{result}\n\\end{{verbatim}}\n" return result def html(self): result = escape_newlines(self.src.strip()) + "\n" result = re.sub("@", "^@", result) result = E("div").body(result).cls("code_text").str() return result # -------------------------------------------------------------------------------- if __name__ == "__main__": s = """ int main(int argc, char* argv[]) { //1 One line commented int count = 12; //3 Two lines commented for (int i = 0; i < count; i++) { std::cout << "Counter: " << i << "\n"; } //1 A really long comment for one line. A really long comment for one line. A really long comment for one line. std::cout << "End\n"; } """ get_blocks(s); # class Code(klammer_base.Klammer_base): # def __init__(self, K): # super().__init__(K) # #self.show("Code") # if self.filename and self.text: # raise Exception("Both :text and :filename cannot be defined") # if K.filename: # with open(K.filename) as fp: # self.src = fp.read() # if K.pattern: # rgx = re.compile(f".*?({K.pattern}).*", re.S) # match = rgx.match(self.src) # if match is None: # raise Exception(f"Match fails for @source_code: {K.pattern}") # self.src = match.group(1) # self.src = kutil.protect_klammertext_special_characters(self.src) # else: # self.src = self.text # def html(self): # #src = re.sub("\n", "", self.src) ? # #result = f'
\n{self.src}\n
\n' # result = self.src # result = undash(result) # result = f'
\n{result}\n
\n' # return result # def tex(self): # src = self.src # src = re.sub(r"\\{", "{", src) # src = re.sub(r"\\}", "}", src) # result = f"\\begin{{lstlisting}}\n{src}\n\\end{{lstlisting}}\n" # return result # def txt(self): # return "x~ " + self.src # class Pathname(klammer_base.Klammer_base): # def __init__(self, K): # super().__init__(K) # def html(self): # return f'{self.s}' # def tex(self): # result = self.s # def replace(match): # return '\\{}'.format(match.group(1)) # result = re.sub(r'\\', 'XXXBACKSLASHXXX', result) # result = re.compile('\s*__UNSPACE__\s*', re.S).sub('', result) # result = re.compile(r'([&${}%#_])').sub(replace, result) # result = re.sub('\^', r'\\^{}', result) # result = re.sub('~', r'\\~{}', result) # result = re.sub(r'XXXBACKSLASHXXX', r'{\\textbackslash}', result) # result = re.sub('\n', r'~\\\\\n', result.strip()) # result = re.sub(' ', '$~$', result) # result = re.sub("'", r"{\\textquotesingle}", result) # result = re.sub('"', r'{\\textquotedbl}', result) # result = re.sub('--', '{-}{-}', result) # result = r'{{\normalfont\texttt{{{}}}}}'.format(result.strip()) # result = re.sub(r'\{\\textbackslash\}\\#', '\\#', result) # if self.small: # result = '{{\\footnotesize{}}}'.format(result) # return result # def txt(self): # return f"'{self.s}'"