| ... | @@ -89,41 +89,98 @@ fn renderRoot( | ... | @@ -89,41 +89,98 @@ fn renderRoot( |
| 89 | var it = tree.root_node.decls.iterator(0); | 89 | var it = tree.root_node.decls.iterator(0); |
| 90 | while (true) { | 90 | while (true) { |
| 91 | var decl = (it.next() orelse return).*; | 91 | var decl = (it.next() orelse return).*; |
| 92 | // look for zig fmt: off comment | 92 | |
| 93 | var start_token_index = decl.firstToken(); | 93 | // This loop does the following: |
| 94 | zig_fmt_loop: while (start_token_index != 0) { | 94 | // |
| 95 | start_token_index -= 1; | 95 | // - Iterates through line/doc comment tokens that precedes the current |
| 96 | const start_token = tree.tokens.at(start_token_index); | 96 | // decl. |
| 97 | switch (start_token.id) { | 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 | Token.Id.LineComment => {}, | 112 | Token.Id.LineComment => {}, |
| 99 | Token.Id.DocComment => continue, | 113 | Token.Id.DocComment => { |
| | 114 | copy_start_token_index = token_index; |
| | 115 | continue; |
| | 116 | }, |
| 100 | else => break, | 117 | else => break, |
| 101 | } | 118 | } |
| 102 | if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(start_token)[2..], " "), "zig fmt: off")) { | 119 | |
| 103 | var end_token_index = start_token_index; | 120 | if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: off")) { |
| 104 | while (true) { | 121 | if (!found_fmt_directive) { |
| 105 | end_token_index += 1; | 122 | fmt_active = false; |
| 106 | const end_token = tree.tokens.at(end_token_index); | 123 | found_fmt_directive = true; |
| 107 | switch (end_token.id) { | 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 | Token.Id.LineComment => {}, | 152 | Token.Id.LineComment => {}, |
| 109 | Token.Id.Eof => { | 153 | Token.Id.Eof => unreachable, |
| 110 | const start = tree.tokens.at(start_token_index + 1).start; | | |
| 111 | try copyFixingWhitespace(stream, tree.source[start..]); | | |
| 112 | return; | | |
| 113 | }, | | |
| 114 | else => continue, | 154 | else => continue, |
| 115 | } | 155 | } |
| 116 | if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(end_token)[2..], " "), "zig fmt: on")) { | 156 | if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: on")) { |
| 117 | const start = tree.tokens.at(start_token_index + 1).start; | 157 | fmt_active = true; |
| 118 | try copyFixingWhitespace(stream, tree.source[start..end_token.end]); | 158 | } else if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: off")) { |
| 119 | try stream.writeByte('\n'); | 159 | fmt_active = false; |
| 120 | while (tree.tokens.at(decl.firstToken()).start < end_token.end) { | | |
| 121 | decl = (it.next() orelse return).*; | | |
| 122 | } | | |
| 123 | break :zig_fmt_loop; | | |
| 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 | try renderTopLevelDecl(allocator, stream, tree, 0, &start_col, decl); | 186 | try renderTopLevelDecl(allocator, stream, tree, 0, &start_col, decl); |