| ... | ... | @@ -89,41 +89,98 @@ fn renderRoot( |
| 89 | 89 | var it = tree.root_node.decls.iterator(0); |
| 90 | 90 | while (true) { |
| 91 | 91 | var decl = (it.next() orelse return).*; |
| 92 | | // look for zig fmt: off comment |
| 93 | | var start_token_index = decl.firstToken(); |
| 94 | | zig_fmt_loop: while (start_token_index != 0) { |
| 95 | | start_token_index -= 1; |
| 96 | | const start_token = tree.tokens.at(start_token_index); |
| 97 | | switch (start_token.id) { |
| 92 | |
| 93 | // This loop does the following: |
| 94 | // |
| 95 | // - Iterates through line/doc comment tokens that precedes the current |
| 96 | // decl. |
| 97 | // - Figures out the first token index (`copy_start_token_index`) which |
| 98 | // hasn't been copied to the output stream yet. |
| 99 | // - Detects `zig fmt: (off|on)` in the line comment tokens, and |
| 100 | // determines whether the current decl should be reformatted or not. |
| 101 | // |
| 102 | var token_index = decl.firstToken(); |
| 103 | var fmt_active = true; |
| 104 | var found_fmt_directive = false; |
| 105 | |
| 106 | var copy_start_token_index = token_index; |
| 107 | |
| 108 | while (token_index != 0) { |
| 109 | token_index -= 1; |
| 110 | const token = tree.tokens.at(token_index); |
| 111 | switch (token.id) { |
| 98 | 112 | Token.Id.LineComment => {}, |
| 99 | | Token.Id.DocComment => continue, |
| 113 | Token.Id.DocComment => { |
| 114 | copy_start_token_index = token_index; |
| 115 | continue; |
| 116 | }, |
| 100 | 117 | else => break, |
| 101 | 118 | } |
| 102 | | if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(start_token)[2..], " "), "zig fmt: off")) { |
| 103 | | var end_token_index = start_token_index; |
| 104 | | while (true) { |
| 105 | | end_token_index += 1; |
| 106 | | const end_token = tree.tokens.at(end_token_index); |
| 107 | | switch (end_token.id) { |
| 119 | |
| 120 | if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: off")) { |
| 121 | if (!found_fmt_directive) { |
| 122 | fmt_active = false; |
| 123 | found_fmt_directive = true; |
| 124 | } |
| 125 | } else if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: on")) { |
| 126 | if (!found_fmt_directive) { |
| 127 | fmt_active = true; |
| 128 | found_fmt_directive = true; |
| 129 | } |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | if (!fmt_active) { |
| 134 | // Reformatting is disabled for the current decl and possibly some |
| 135 | // more decls that follow. |
| 136 | // Find the next `decl` for which reformatting is re-enabled. |
| 137 | token_index = decl.firstToken(); |
| 138 | |
| 139 | while (!fmt_active) { |
| 140 | decl = (it.next() orelse { |
| 141 | // If there's no next reformatted `decl`, just copy the |
| 142 | // remaining input tokens and bail out. |
| 143 | const start = tree.tokens.at(copy_start_token_index).start; |
| 144 | try copyFixingWhitespace(stream, tree.source[start..]); |
| 145 | return; |
| 146 | }).*; |
| 147 | var decl_first_token_index = decl.firstToken(); |
| 148 | |
| 149 | while (token_index < decl_first_token_index) : (token_index += 1) { |
| 150 | const token = tree.tokens.at(token_index); |
| 151 | switch (token.id) { |
| 108 | 152 | Token.Id.LineComment => {}, |
| 109 | | Token.Id.Eof => { |
| 110 | | const start = tree.tokens.at(start_token_index + 1).start; |
| 111 | | try copyFixingWhitespace(stream, tree.source[start..]); |
| 112 | | return; |
| 113 | | }, |
| 153 | Token.Id.Eof => unreachable, |
| 114 | 154 | else => continue, |
| 115 | 155 | } |
| 116 | | if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(end_token)[2..], " "), "zig fmt: on")) { |
| 117 | | const start = tree.tokens.at(start_token_index + 1).start; |
| 118 | | try copyFixingWhitespace(stream, tree.source[start..end_token.end]); |
| 119 | | try stream.writeByte('\n'); |
| 120 | | while (tree.tokens.at(decl.firstToken()).start < end_token.end) { |
| 121 | | decl = (it.next() orelse return).*; |
| 122 | | } |
| 123 | | break :zig_fmt_loop; |
| 156 | if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: on")) { |
| 157 | fmt_active = true; |
| 158 | } else if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: off")) { |
| 159 | fmt_active = false; |
| 124 | 160 | } |
| 125 | 161 | } |
| 126 | 162 | } |
| 163 | |
| 164 | // Found the next `decl` for which reformatting is enabled. Copy |
| 165 | // the input tokens before the `decl` that haven't been copied yet. |
| 166 | var copy_end_token_index = decl.firstToken(); |
| 167 | token_index = copy_end_token_index; |
| 168 | while (token_index != 0) { |
| 169 | token_index -= 1; |
| 170 | const token = tree.tokens.at(token_index); |
| 171 | switch (token.id) { |
| 172 | Token.Id.LineComment => {}, |
| 173 | Token.Id.DocComment => { |
| 174 | copy_end_token_index = token_index; |
| 175 | continue; |
| 176 | }, |
| 177 | else => break, |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | const start = tree.tokens.at(copy_start_token_index).start; |
| 182 | const end = tree.tokens.at(copy_end_token_index).start; |
| 183 | try copyFixingWhitespace(stream, tree.source[start..end]); |
| 127 | 184 | } |
| 128 | 185 | |
| 129 | 186 | try renderTopLevelDecl(allocator, stream, tree, 0, &start_col, decl); |