Files
textmate/Frameworks/regexp/tests/t_indent.cc
Allan Odgaard d16f3bcc1e Use per-line indent patterns when estimating indent
This solves the problem where we need to estimate the current line’s indent, but the lines above it is a multi-line block comment. Previously we would fetch indent patterns based on the current scope, then find the first line above caret, for which the patterns can be used to estimate the indent. The problem is that the commented lines without comment markers would be treated as code, and used for the indent.

With the new approach, we can set different patterns for ‘comment.block’ (the C bundle already does this), which basically ignore all the lines, which will cause TextMate to use the code above the comment to estimate indent.

This commit closes textmate/c.tmbundle#3 and also closes textmate/php.tmbundle#24.
2013-03-13 12:38:12 +01:00

208 lines
5.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <regexp/indent.h>
#include <text/format.h>
#include <oak/oak.h>
struct line_t
{
size_t indent; std::string content;
};
class IndentTests : public CxxTest::TestSuite
{
static std::map<indent::pattern_type, regexp::pattern_t> const& patterns ()
{
static std::map<indent::pattern_type, regexp::pattern_t> const res =
{
{ indent::pattern_type::kIncrease,
"(?x)"
" ^ .* \\{ [^}\"']* $"
"| ^ \\s* (public|private|protected): \\s* $"
"| ^ \\s* @(public|private|protected) \\s* $",
},
{ indent::pattern_type::kDecrease,
"(?x)"
" ^ (.*\\*/)? \\s* \\} ( [^}{\"']* \\{ | \\s* while \\s* \\( .* )? [;\\s]* (//.*|/\\*.*\\*/\\s*)? $"
" | ^ \\s* (public|private|protected): \\s* $"
" | ^ \\s* @(public|private|protected) \\s* $",
},
{ indent::pattern_type::kIncreaseNext,
"(?x)^"
" (?! .* [;:{}] # do not indent when line ends with ;, :, {, or }\n"
" \\s* (//|/[*] .* [*]/ \\s* $) # …account for potential trailing comment\n"
" | @(public|private|protected) # do not indent after obj-c data access keywords\n"
" )"
" .* [^\\s;:{}] \\s* $ # indent next if this one isnt\n"
" # terminated with ;, :, {, or }\n",
},
{ indent::pattern_type::kIgnore,
"^\\s*((/\\*|\\*/|//|#|template\\b.*?>(?!\\(.*\\))|@protocol|@optional|@interface(?!.*\\{)|@implementation|@end).*)?$"
}
};
return res;
}
static size_t const indentSize = 4;
static size_t const tabSize = 4;
public:
void test_indent ()
{
static line_t const lines[] =
{
{ 0, "#include <foo>" },
{ 0, "" },
{ 0, "int main ()" },
{ 0, "{" },
{ 1, "while(true)" },
{ 2, "putc('x');" },
{ 1, "" },
{ 1, "if(true)" },
{ 1, "{" },
{ 2, "while(true)" },
{ 3, "putc('x');" },
{ 2, "if(true)" },
{ 3, "if(true)" },
{ 4, "if(true)" },
{ 5, "continue;" },
{ 1, "}" },
{ 1, "" },
{ 1, "return 42;" },
{ 0, "}" },
};
indent::fsm_t fsm(indentSize, tabSize);
iterate(line, lines)
{
TSM_ASSERT_EQUALS(text::format("%td: %s", line - std::begin(lines), line->content.c_str()), fsm.scan_line(line->content, patterns()), indentSize * line->indent);
}
}
void test_seeding_proper_1 ()
{
static std::string const seed_lines[] =
{
"void main ()",
"{",
" if(true)",
" if(true)",
" if(true)",
};
indent::fsm_t fsm(indentSize, tabSize);
for(size_t i = sizeofA(seed_lines); i-- && !fsm.is_seeded(seed_lines[i], patterns()); )
continue;
static line_t const lines[] =
{
{ 4, "continue;" },
{ 1, "continue;" },
{ 0, "}" },
};
iterate(line, lines)
{
TSM_ASSERT_EQUALS(text::format("%td: %s", line - std::begin(lines), line->content.c_str()), fsm.scan_line(line->content, patterns()), indentSize * line->indent);
}
}
void test_seeding_proper_2 ()
{
static std::string const seed_lines[] =
{
"void main ()",
"{",
" if(true)",
" if(true)",
" if(true)",
" continue;",
};
indent::fsm_t fsm(indentSize, tabSize);
for(size_t i = sizeofA(seed_lines); i-- && !fsm.is_seeded(seed_lines[i], patterns()); )
continue;
static line_t const lines[] =
{
{ 1, "continue;" },
{ 0, "}" },
};
iterate(line, lines)
{
TSM_ASSERT_EQUALS(text::format("%td: %s", line - std::begin(lines), line->content.c_str()), fsm.scan_line(line->content, patterns()), indentSize * line->indent);
}
}
void test_seeding_improper ()
{
static std::string const seed_lines[] =
{
"void main ()",
"{",
" if(true)",
" if(true)",
" if(true)",
};
indent::fsm_t fsm(indentSize, tabSize);
for(size_t i = sizeofA(seed_lines); i-- && !fsm.is_seeded(seed_lines[i], patterns()); )
continue;
static line_t const lines[] =
{
{ 2, "continue;" },
{ 1, "continue;" },
{ 0, "}" },
};
iterate(line, lines)
{
TSM_ASSERT_EQUALS(text::format("%td: %s", line - std::begin(lines), line->content.c_str()), fsm.scan_line(line->content, patterns()), indentSize * line->indent);
}
}
void test_seeding_extra_indent ()
{
static std::string const seed_lines[] =
{
"void main ()",
"{",
" foo(bar,",
" 42);",
};
indent::fsm_t fsm(indentSize, tabSize);
for(size_t i = sizeofA(seed_lines); i-- && !fsm.is_seeded(seed_lines[i], patterns()); )
continue;
static line_t const lines[] =
{
{ 1, "return 0;" },
{ 0, "}" },
};
iterate(line, lines)
{
TSM_ASSERT_EQUALS(text::format("%td: %s", line - std::begin(lines), line->content.c_str()), fsm.scan_line(line->content, patterns()), indentSize * line->indent);
}
}
void test_mixing ()
{
static line_t const lines[] =
{
{ 0, "int main ()" },
{ 0, "{" },
{ 1, "str = { foo," },
{ 2, "bar };" },
{ 1, "}" },
};
indent::fsm_t fsm(indentSize, tabSize);
iterate(line, lines)
{
TSM_ASSERT_EQUALS(text::format("%td: %s", line - std::begin(lines), line->content.c_str()), fsm.scan_line(line->content, patterns()), indentSize * line->indent);
}
}
};