tty.ha (4443B)
1 // SPDX-License-Identifier: GPL-3.0-only 2 // (c) Hare authors <https://harelang.org> 3 4 use bufio; 5 use fmt; 6 use hare::ast; 7 use hare::lex; 8 use hare::unparse; 9 use io; 10 use os; 11 use strings; 12 13 let no_color: bool = false; 14 15 // Formats output as Hare source code (prototypes) with syntax highlighting 16 export fn emit_tty(ctx: *context) (void | error) = { 17 if (os::tryenv("NO_COLOR", "") == "") { 18 init_colors()?; 19 } else { 20 no_color = true; 21 }; 22 const summary = ctx.summary; 23 24 if (ctx.ambiguous) { 25 const id = unparse::identstr(ctx.ident); 26 defer free(id); 27 28 if (!no_color) fmt::fprintf(ctx.out, "\x1b[{}m", 29 color(unparse::synkind::COMMENT))?; 30 fmt::fprint(ctx.out, "// ")?; 31 if (!no_color) fmt::fprint(ctx.out, "\x1b[93m")?; 32 fmt::fprint(ctx.out, "NOTE")?; 33 if (!no_color) fmt::fprintf(ctx.out, "\x1b[m" "\x1b[{}m", 34 color(unparse::synkind::COMMENT))?; 35 fmt::fprintf(ctx.out, ": {} also refers to module [[{}::]]", 36 id, id)?; 37 if (!no_color) fmt::fprint(ctx.out, "\x1b[m")?; 38 fmt::fprintln(ctx.out, "\n")?; 39 }; 40 41 if (len(ctx.parse_errs) > 0) { 42 if (!no_color) fmt::fprintf(ctx.out, "\x1b[{}m", 43 color(unparse::synkind::COMMENT))?; 44 fmt::fprint(ctx.out, "// ")?; 45 if (!no_color) fmt::fprint(ctx.out, "\x1b[93m")?; 46 fmt::fprint(ctx.out, "WARNING")?; 47 if (!no_color) fmt::fprintf(ctx.out, "\x1b[m" "\x1b[{}m", 48 color(unparse::synkind::COMMENT))?; 49 fmt::fprintln(ctx.out, 50 ": parsing errors occurred; documentation may be incomplete")?; 51 if (!no_color) fmt::fprint(ctx.out, "\x1b[m")?; 52 }; 53 for (let i = 0z; i < len(ctx.parse_errs); i += 1) { 54 fmt::fprintln(ctx.out, "//", lex::strerror(ctx.parse_errs[i]))?; 55 }; 56 if (len(ctx.parse_errs) > 0) { 57 fmt::fprintln(ctx.out)?; 58 }; 59 60 match (ctx.readme) { 61 case let readme: io::file => 62 let rbuf: [os::BUFSZ]u8 = [0...]; 63 let readme = bufio::init(readme, rbuf, []); 64 let sc = bufio::newscanner(&readme); 65 defer bufio::finish(&sc); 66 for (let line => bufio::scan_line(&sc)?) { 67 firstline = false; 68 if (!no_color) fmt::fprintf(ctx.out, "\x1b[{}m", 69 color(unparse::synkind::COMMENT))?; 70 fmt::fprint(ctx.out, "//", line)?; 71 if (!no_color) fmt::fprint(ctx.out, "\x1b[m")?; 72 fmt::fprintln(ctx.out)?; 73 }; 74 case void => void; 75 }; 76 77 emit_submodules_tty(ctx)?; 78 79 // XXX: Should we emit the dependencies, too? 80 let printed = false; 81 for (let t &.. summary.types) { 82 if (details_tty(ctx, t)?) { 83 printed = true; 84 }; 85 }; 86 for (let c &.. summary.constants) { 87 if (details_tty(ctx, c)?) { 88 printed = true; 89 }; 90 }; 91 for (let e &.. summary.errors) { 92 if (details_tty(ctx, e)?) { 93 printed = true; 94 }; 95 }; 96 for (let g &.. summary.globals) { 97 if (details_tty(ctx, g)?) { 98 printed = true; 99 }; 100 }; 101 for (let f &.. summary.funcs) { 102 if (details_tty(ctx, f)?) { 103 printed = true; 104 }; 105 }; 106 107 if (!printed) { 108 if (!firstline) { 109 fmt::fprintln(ctx.out)?; 110 }; 111 if (!no_color) fmt::fprintf(ctx.out, "\x1b[{}m", 112 color(unparse::synkind::COMMENT))?; 113 fmt::fprint(ctx.out, "// No exported declarations")?; 114 if (!no_color) fmt::fprint(ctx.out, "\x1b[m")?; 115 fmt::fprintln(ctx.out)?; 116 }; 117 }; 118 119 fn emit_submodules_tty(ctx: *context) (void | error) = { 120 if (len(ctx.submods) != 0) { 121 if (!firstline) { 122 fmt::fprintln(ctx.out)?; 123 }; 124 firstline = false; 125 if (!no_color) fmt::fprintf(ctx.out, "\x1b[{}m", 126 color(unparse::synkind::COMMENT))?; 127 if (len(ctx.ident) == 0) { 128 fmt::fprintln(ctx.out, "// Modules")?; 129 } else { 130 fmt::fprintln(ctx.out, "// Submodules")?; 131 }; 132 for (let submodule .. ctx.submods) { 133 let submodule = if (len(ctx.ident) != 0) { 134 const s = unparse::identstr(ctx.ident); 135 defer free(s); 136 yield strings::concat(s, "::", submodule); 137 } else { 138 yield strings::dup(submodule); 139 }; 140 defer free(submodule); 141 142 fmt::fprintfln(ctx.out, "// - [[{}::]]", submodule)?; 143 }; 144 }; 145 }; 146 147 fn details_tty(ctx: *context, decl: *ast::decl) (bool | error) = { 148 if (len(decl.docs) == 0 && !ctx.show_undocumented) { 149 return false; 150 }; 151 152 if (!no_color) fmt::fprint(ctx.out, "\x1b[m")?; // reset styling 153 if (!firstline) { 154 fmt::fprintln(ctx.out)?; 155 }; 156 firstline = false; 157 158 unparse::decl(ctx.out, &syn_tty, decl)?; 159 fmt::fprintln(ctx.out)?; 160 return true; 161 }; 162 163 fn syn_tty( 164 ctx: *unparse::context, 165 s: str, 166 kind: unparse::synkind, 167 ) (size | io::error) = { 168 let z = 0z; 169 if (!no_color) z += fmt::fprintf(ctx.out, "\x1b[{}m", color(kind))?; 170 z += unparse::syn_wrap(ctx, s, kind)?; 171 if (!no_color) z += fmt::fprint(ctx.out, "\x1b[m")?; 172 return z; 173 };