diff --git a/autotests/folding/Makefile.fold b/autotests/folding/Makefile.fold
index 1cea5dd..4223e0b 100644
--- a/autotests/folding/Makefile.fold
+++ b/autotests/folding/Makefile.fold
@@ -1,28 +1,28 @@
# comment
include Makefile.in
-include Makefile.doesntexist
.PHONY: all
all: target
foo = bar $(var) \
$(baz) quux
ifeq ($(CC),gcc)
bla=$(call func,param1,param2)
-else ifeq "x" "y"else ifeq "x" "y"
+else ifeq "x" "y"
$(error this seems wrong)
-elseelse
+else
libs=$(normal_libs)
endif
target1:
error
target2: bla.cpp $@
$(CC) bla.c -o bla.o
$(CC) bla.o $< \
-o bla.exe
@echo "hello"
diff --git a/autotests/folding/folding.cpp.fold b/autotests/folding/folding.cpp.fold
index 14dccf2..9966389 100644
--- a/autotests/folding/folding.cpp.fold
+++ b/autotests/folding/folding.cpp.fold
@@ -1,15 +1,15 @@
/**
* multi-line comment
*/
/* comment */
{ { } {
//BEGIN
}
//END
}
#if 0
-#elif 1#elif 1
-#else#else
+#elif 1
+#else
#endif
diff --git a/autotests/folding/highlight.asp.fold b/autotests/folding/highlight.asp.fold
index b938201..794097b 100644
--- a/autotests/folding/highlight.asp.fold
+++ b/autotests/folding/highlight.asp.fold
@@ -1,58 +1,58 @@
<% 'kate: hl ASP;
if ( instr(request.servervariables("PATH_INFO"),"login.asp") <= 0 and instr(request.servervariables("PATH_INFO"),"inset") <= 0 and instr(request.servervariables("PATH_INFO"),"Data") <= 0 and instr(request.servervariables("PATH_INFO"),"dropDown") <= 0 ) then
Session("originalRequestedPage") = Request.ServerVariables("PATH_INFO") & "?" & Request.ServerVariables("QUERY_STRING")
end if
function countRecords( rsToCount )
numRecs = 0
do until rsToCount.eof
numRecs = numRecs + 1
rsToCount.movenext
loop
rsToCount.close ' just to make sure nobody
' tries to operate on the recordset,
' which has already reached eof
countRecords = numRecs
end function
function unique( rs, sortColumn ) ' return unique instances of text in sortColumn within rs
dim sorted()
redim sorted(1)
dim i
i = 0
do until rs.eof
if (not find( rs(sortColumn), sorted )) then
redim preserve sorted(i+1)
sorted(i) = rs(sortColumn)
i = i + 1
end if
rs.MoveNext
loop
redim preserve sorted(i-1) ' the function will add an extra blank entry to the array
rs.Close ' close the recordset - we'll be using it again - and reset i - well be using it again, too
unique = sorted
end function
sub testSub( variable ) ' do nothing impressive...
dim newVar
newVar = variable
if ( variable = true )
response.end
- else %>else %>
+ else %>
We are writing text.
<%=newVar%>
We have written text and outputted a variable.
<% end if
end sub %>
diff --git a/autotests/folding/highlight.cpp.fold b/autotests/folding/highlight.cpp.fold
index 24c6949..65c8b43 100644
--- a/autotests/folding/highlight.cpp.fold
+++ b/autotests/folding/highlight.cpp.fold
@@ -1,507 +1,507 @@
#pragma once
#include
#include
#include "assert.h"
#include "assert.hpp" // abc
#include "path/assert.hpp"
#include "assert.h"a
#include "assert.h" a
#include a
#include a
#include FOO() error
#include_next a
#include_next /* a
*/ b
#include PATH_IN_MACRO
#include PATH_IN_MACRO()
#include PATH_IN_MACRO(a, b)
#define SOME_VAR 1
#ifdef SOME_VAR
#define MULTILINE_MACRO one \
two \
three
# define MULTILINE_MACRO_TEXT \
/* NOTE The contents of macro is too green :D */ \
char const s[] = "a\\b" \
"c\nd"
# define VARIADIC(a, ...) \
f(a##a) \
f(__VA_ARGS__) \
f(#__VA_ARGS__) \
f(__VA_ARGS__) \
f(0 __VA_OPT__(,) __VA_ARGS__) \
x __VA_OPT__(= { __VA_ARGS__ })
# define MACRO() BAD \ ESCAPED
# error dds
# warning dds
# line 2 "file.cpp"
# define A(x, y) x##y x#y
// OK(L, a) -> L"a"
# define OK(x, y) x###y
# define BAD(x, y) x####y
# define A /* multi line
with comment */ expr
# define A /* multi line
with comment */
23
-#else // xelse // x
+#else // x
#42 // gcc extension = #line 42
// error
#wrong
# wrong
#endif x
#if DS()
-#else xelse x
-#else /* */xelse /* */x
-#else /* xelse /* x
+#else x
+#else /* */x
+#else /* x
y */ z
#endif
// check that _XXX defines work, bug 397766
#ifndef _HEADER_GUARD
#define _HEADER_GUARD 1
#endif
#ifdef _HEADER_GUARD
#if (_HEADER_GUARD >= 1)
#endif
#endif
static int g_global;
template class = std::is_pointer>
struct class1
: private std::vector, public U
{
class1()
try
: _member1(xxx)
{}
catch(...)
{}
class1(class1&&) = default;
~class1()
{}
void foo() { return; }
void foo() const { return; }
void foo() noexcept { return; }
void foo() const noexcept { return; }
virtual void foo() const noexcept { return; }
static void foo() { return; }
constexpr static void foo() const
noexcept(noexcept(std::is_pointer::value)) override
{
xxx::template ttt::type {};
xxx.template get();
xxx.std::rdbuf();
auto x = C<'a'> + y;
}
int operator->*(T (C::*m)(int));
operator value_t ();
private:
protected:
public:
value_type _member1; // NOTE internal ?
value_type __internal;
value_type internal__;
value_type _M_internal;
value_t member2_;
value_type m_member3;
static int s_static;
static constexpr int s_static;
static inline int s_static;
static inline constexpr int s_static;
};
constexpr struct : xyz
{
using xyz::xyz;
using xyz::operator=;
int a : 1;
int b : 7;
} x {};
template
using is_pointer = std::is_pointer::type;
template
constexpr auto is_pointer_v = std::is_pointer::value;
uint64_t namespaces()
{
std::vector;
boost::vector;
detail::vector;
details::vector;
aux::vector;
internals::vector;
other::vector;
}
#if 1
double foo(const A);
-#else // else#else // else
+#else // else
double foo(const A);
#endif // end
#if 0
double foo(const A);
-#else // else#else // else
+#else // else
double foo(const A);
#endif // end
#if 1
double foo(const A);
-#elif 1#elif 1
+#elif 1
double foo(const A);
#elif 0
double foo(const A);
#endif // end
#if 0
double foo(const A);
-#elif 1#elif 1
+#elif 1
double foo(const A);
-#elif 0#elif 0
+#elif 0
double foo(const A);
#endif // end
#if 0
double foo(const A);
-#elif a#elif a
+#elif a
double foo(const A);
#elif 0
double foo(const A);
-#elif a#elif a
+#elif a
double foo(const A);
-#else // elseelse // else
+#else // else
double foo(const A);
#endif // end
#if 0 // blah blah
double foo(const A);
-#elif 1 // blah blah#elif 1 // blah blah
+#elif 1 // blah blah
double foo(const A);
-#else // else#else // else
+#else // else
double foo(const A);
#endif // end
#if 0 || a
double foo(const A);
-#else // elseelse // else
+#else // else
double foo(const A);
#endif // end
#if 1 || a
double foo(const A);
-#else // else#else // else
+#else // else
double foo(const A);
#endif // end
#if 0 && a
double foo(const A);
-#else // elseelse // else
+#else // else
double foo(const A);
#endif // end
#if 1 && a
double foo(const A);
-#else // elseelse // else
+#else // else
double foo(const A);
#endif // end
#if a
double foo(const A);
#elif 0
double foo(const A);
#endif // end
#if a
double foo(const A);
#elif 1
double foo(const A);
#endif // end
#if a
double foo(const A);
#elif a
double foo(const A);
#endif // end
int bar(void*p, void * pp)
{
# if 0
double foo();
-# else // else# else // else
+# else // else
double foo();
# endif // end
}
#if abc 0
double foo();
#endif // end
#if xxx
double foo();
-#elseelse
+#else
double foo();
#endif // end
#if xxx
double foo();
#elif xxx // elseif
double foo();
#elif xxx // elseif
double foo();
#endif // end
// error
#
#d
# d
#if
#elif
#endif
#ifndef
#endif
#ifdef 0
#endif // end
static uint64_t intWithSuffix = 42ull;
static long intWithSuffixAndPrefix = 0b0101L;
static int octNum = 07232;
static int invalidOctNum = 09231;
static uint64_t hexNum = 0xDEADBEEF42;
static uint64_t invalidHexNum = 0xGLDFKG;
static char binNum = 0b0101010;
static int64_t intWithSuffix = -42LL;
static long intWithSuffixAndPrefix = -0b0101L;
static int octNum = -07232;
static int invalidOctNum = -09231;
static int64_t hexNum = -0xDEADBEEF42;
static int64_t invalidHexNum = -0xGLDFKG;
static char binNum = -0b0101010;
static uint64_t intWithSuffixWithSep = 4'2ull;
static long intWithSuffixAndPrefixWithSep = 0b0'10'1L;
static int octNumWithSep = 07'232;
static int invalidOctNumWithSep = 09'23'1;
static uint64_t hexNumWithSep = 0xD'EAD'BE'EF'42;
static uint64_t invalidHexNumWithSep = 0xGLD'FKG;
static char binNumWithSep = 0b0'1010'10;
static uint64_t invalidSep = 42'ull;
static uint64_t invalidSep = 42';
static double d1 = 42.;
static double d2 = .42;
static double d2a = -0.49;
static double d2b = -0.09;
static double d3 = 42.3e1;
static double d4 = .2e-12;
static double d5 = 32.e+12;
static double invalidD1 = 32.e+a12;
static float floatQualifier = 23.123f;
// Hexadecimal floating point (c++17)
static double d6 = 0x1ffp10;
static double d7 = 0X0p-1;
static double d8 = 0x1.p0;
static double d9 = 0xf.p-1L;
static double d10 = 0x0.123p-1;
static double d11 = 0xa.bp10l;
static double invalidD2 = 0x0.123p-a;
static float floatQualifier = 0xf.p-1f;
60min; // c++17
60.min;
60.3min;
0x1ffp10min;
2d; // c++20
23._f
23._fd
2.3_f
2.3_fd
2._f
2._fd
2e4_f
2e4_fd
// error
23.fd
2e_fd
2e
1.y
1.0_E+2.0
1.0_E +2.0 // ok
1_p+2
1_p +2 // ok
4s.count()
4s. count()
4s .count() // ok
static bool yes = true;
static bool no = false;
// *char*
static const char c1 = 'c';
static const char c1a = u8'c'; // utf-8 char (c++17)
static const char16_t c1b = u'c';
static const char32_t c1c = U'c';
static const wchar_t c1d = L'c';
static const char c2 = '\n';
static const char c2a = '\120'; // octal
static const char c2b = '\x1f'; // hex
static const char c2c = '\'';
static const char c2d = '\\';
static const wchar_t c2e = L'\x1ff'; // hex
static const wchar_t c2e = U'\x1fffffff'; // hex
// error
'\x123';
'\u1234';
'\U12345678';
U'\u12345';
u'\u123';
U'\U1234567';
U'\U123456789';
U'\x123456789';
// string
static const char* c3 = "string";
static const char* c4 = "\"string\n\t\012\x12\"";
static const char* c5 = "multiline \
string";
static const char* c6 = "multifragment" "other""string";
static const char* c6a = u8"string";
static const char16_t* c6b = u"string";
static const char32_t* c6c = U"string";
static const wchar_t* c6d = L"string";
static const char* rawString1 = R"(string)";
static const char* rawString1a = u8R"(string)";
static const char16_t* rawString1b = uR"(string)";
static const char32_t* rawString1c = UR"(string)";
static const wchar_t* rawString1d = LR"(string\nstring)";
static const char* rawString2 = R"ab(string\nstring)ab";
static const char* rawString3 = R"ab(string
string)ab";
" %d %df fd" U"ds %d" R"(a%d)";
"\x123xsk";
u"\x123xsk";
// error
u8"\x123xsk";
// UDL (c++11)
operator""_a(const char*);
operator ""_a(const char*);
operator "" _a(const char*);
// invalid suffix
operator "" a(const char*);
operator ""a(const char*);
operator""a(const char*);
"string"_s; // user
"string"s; // standard
"string"_s-b; // -b is not part of the string
// Macro
MY_XXX;
BOOST_XXX;
__STDC_VERSION__;
__TIME__;
__cplusplus;
// Attributes
[[noreturn]] void foo();
[[deprecated]] void foo();
[[deprecated("because")]] void foo();
void foo([[carries_dependency]] int);
[[opt(1), debug]]
[[using CC: opt(1), debug]] // c++17
[[using CC: CC::opt(1)]] // c++17
[[gnu::assume_aligned(3'2l,2)]] void* f();
[[using gnu: assume_aligned(3)]]
[[clang::assume_aligned(3)]]
void f([[maybe_unused]] int val)
{
[[maybe_unused]] int x;
switch (x = foo(); x) {
case 1:
[[fallthrough]];
case XXX:
case Class::foo():
[[fallthrough]];
default:
;
}
// c++17: fold expression
(args + ... + (1 * 2));
(v.push_back(args), ...);
[[omp::parallel]] for (auto&& x : v)
x;
for (auto&& [first,second] : mymap) {
}
auto [x, y] = foo();
[x = 1, =y](){};
decltype((auto)) x = foo();
}
auto f() -> decltype(foo());
__attribute__((pure)) void f();
label:
goto label;
//BEGIN region
// TODO comment FIXME comment ### comment BUG comment
//END region
// \brief blah blah
/// \brief blah blah
/**
* Doxygen
* @param p1 text
* \brief bold text
* \dot
* a -> b
* \enddot
*
* \verbatim
*
* \endverbatim
* text
*/
#endif
// Some GNU macros, cross-referenced from gcc.xml to isocpp.xml
__GCC_ATOMIC_CHAR16_T_LOCK_FREE
__GNUC__
__linux__
diff --git a/autotests/folding/highlight.f90.fold b/autotests/folding/highlight.f90.fold
index 2ea0f76..94fe78d 100644
--- a/autotests/folding/highlight.f90.fold
+++ b/autotests/folding/highlight.f90.fold
@@ -1,181 +1,181 @@
! This file is an example to test the syntax highlighting file F.xml
! (for fortran 90 and F)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! THIS IS AN EXAMPLE OF A MODULE !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
module module_example
! use 'implicit none' when you want all variables to be declared
implicit none
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! PUBLICS AND PRIVATES
! In fortran 90 you can define your own operator
public :: operator(.norm.)
public :: operator(+) ! <-- you can also overload the usual operators
public :: factorial
public :: example_fn
private :: point3d_add
private :: point3d_norm
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! USER-DEFINED TYPES...
! This is a definition to use in declarations of real variables,
! parameters, etc.
integer, parameter, public :: kr = selected_real_kind(10)
! This is a user-defined type
type, public :: point3d
real(kind=kr) :: x, y, z
end type point3d
! This type is useless: it is only an example of type definition!
type, public :: example_type
complex(kind=kr) :: c ! <-- a complex number (two reals of kind kr)!
real, dimension(-10:10) :: & ! <-- this line does not end here!
r1, r2 ! <-- this is the final part of the previous line
real, pointer, dimension(:) :: pointer_to_array_of_real
real, dimension(:), pointer :: array_of_pointer_to_real
end type example_type
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! INTERFACES...
! Interface for the norm of a 3-D vector
interface operator(.norm.)
module procedure point3d_norm
end interface
! Interface for the operator '+'
interface operator(+)
module procedure point3d_add
end interface
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! SOME DECLARATIONS...
! A real number can be declared with the following line:
real(kind=kr) :: real_var1
! But if you are not interested on the precision of floating point numbers,
! you can use simply:
real :: real_var2
! An array can be declared in two ways:
real(kind=kr), dimension(1:10, -4:5), private :: a, b, c
real(kind=kr), private :: d(1:10, -4:5)
! This is a string with fixed lenght
character(len=10) :: str_var
! This is an allocatable array, which can be a target of a pointer
type(example_type), private, dimension(:), allocatable, target :: &
many_examples
! Fortran 90 hasn't got its own preprocessor, it uses the C preprocessor!
#ifdef XXX
c <-- this is a comment in the old fortran 77 style (fixed form)
c This is a free form file, so we shouldn't use this kind of comments!
c But fortran 90 still understands fixed form, when parsing sources with
c the *.f extension.
c ! <-- this 'c' shouldn't be highlighted as a comment!
#endif
contains
! The sum of two points
pure function point3d_add(a, b) result(rs)
type(point3d) :: rs
type(point3d), intent(in) :: a, b
rs%x = a%x + b%x
rs%y = a%y + b%y
rs%z = a%z + b%z
end function point3d_add
! The norm of a point
pure function point3d_norm(a) result(rs)
real(kind=kr) :: rs
type(point3d), intent(in) :: a
rs = sqrt(a%x * a%x + a%y * a%y + a%z * a%z)
end function point3d_norm
! A simple recursive function
recursive function factorial(i) result (rs)
integer :: rs
integer, intent(in) :: i
if ( i <= 1 ) then
rs = 1
- elseelse
+ else
rs = i * factorial(i - 1)
end if
end function factorial
! This is a useless function
subroutine example_fn(int_arg, real_arg, str_arg)
integer, intent(in) :: int_arg
real(kind=kr), intent(out) :: real_arg
character(len=*), intent(in) :: str_arg
type(example_type), pointer :: p
integer :: n, i, j
logical :: flag
flag = .true. ! .true. is not an operator!
if ( flag .and. flag ) then ! .and. is a pre-defined operator
print *, "blabla"
end if
! Examples of inquiry functions: allocated, lbound, ubound.
if ( .not. allocated(many_examples) ) then
allocate( many_examples(10) )
end if
print *, "Lower bound = ", lbound(many_examples, 1)
print *, "Upper bound = ", ubound(many_examples, 1)
p => many_examples(5) ! <-- p is a pointer
! A strange way to calculate i*i: add the first i odd numbers
i = 6
j = 0
do n = 1, i
j = j + (2*n - 1)
end do
print *, "i*i = ", i*i, j
real_arg = real(j) ! <-- here the highlighting is not very good:
! it is unable to distinguish between this and a definition like:
! real(kind=kr) :: a
deallocate( many_examples )
end subroutine example_fn
end module module_example
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! THIS IS THE MAIN PROGRAM !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
program example
use module_example
! this is another example of use of the 'implicit' keyword
implicit double precision (a-h,o-z)
real(kind=kr) :: var_out
type(point3d) :: &
a = point3d(0.0_kr, 1.0_kr, 2.0_kr), &
b = point3d(4.0_kr, 5.0_kr, 6.0_kr)
print *, "a + b = ", .norm. (a + b)
print *, "factorial of 5 = ", factorial(5)
call example_fn(1, var_out, "hello!")
end program example
diff --git a/autotests/folding/highlight.lex.fold b/autotests/folding/highlight.lex.fold
index b18a107..f6535bf 100644
--- a/autotests/folding/highlight.lex.fold
+++ b/autotests/folding/highlight.lex.fold
@@ -1,82 +1,82 @@
/* This test file tests kates Lex/Flex highlighting */
%option c++
%option yyclass="KateTester"
%option yylineno
/* This is a C(++) comment */
/* This one is a lex comment ! */
%{
#include
#include "realparser.hpp"
using namespace std;
%}
/* Some definitions */
DIGIT [0-9]
LETTER [_a-zA-Z]
-%%%%
+%%
/* Comment *shall be indented here* */
[ \t\n\r]+
/* Note: there is a bad } just here vvv */
\/\*([^\*]|\*[^/])*\*\/ { foo(a, b, c); } }
/* A start condition scope... */
{
"a" {
/* C mode ! */
return 0;
}
"b" %{
/* C mode, too ! */
return 0;
%}
"c" return 0; // C++ comment
}
/* Big rule */
\"([^"\\]|\\.)*\" {
yylval.string_val = new char[strlen(yytext) + 1];
int j = 0, i = 1;
while (yytext[i] != '"')
if (yytext[i] != '\\')
yylval.string_val[j++] = yytext[i++];
else
switch (yytext[i + 1])
{
case 'n':
yylval.string_val[j++] = '\n'; i += 2;
break;
default:
yylval.string_val[j++] << yytext[i + 1], i += 2;
}
yylval.string_val[j] = 0;
return TOK_STRING;
}
/* Dot (match all) */
. {return yylval.int_val = yytext[0];}
-%%%%
+%%
// Here is pure C(++)
#include
int main(void)
{
std::cout << "Hello, World\n";
return 0;
}
diff --git a/autotests/folding/highlight.pl.fold b/autotests/folding/highlight.pl.fold
index 6845697..f39931d 100644
--- a/autotests/folding/highlight.pl.fold
+++ b/autotests/folding/highlight.pl.fold
@@ -1,75 +1,75 @@
#!/usr/bin/perl -w
# This is a pseudo Perl file to test Kate's Perl syntax highlighting.
# TODO: this is incomplete, add more syntax examples!
sub prg($)
{
my $var = shift;
- $var =~ s/bla/foo/igs;/foo/igs;
- $var =~ s!bla!foo!igs;!foo!igs;
- $var =~ s#bla#foo#igs;#foo#igs;
+ $var =~ s/bla/foo/igs;
+ $var =~ s!bla!foo!igs;
+ $var =~ s#bla#foo#igs;
$var =~ tr/a-z/A-Z/;
($match) = ($var =~ m/(.*?)/igs);
$test = 2/453453.21;
$test /= 2;
print qq~d fsd fsdf sdfl sd~
$" = '/';
$foo = <<__EOF;
d ahfdklf klsdfl sdf sd
fsd sdf sdfsdlkf sd
__EOF
$x = "dasds";
next if( $match eq "two" );
next if( $match =~ /go/i );
@array = (1,2,3); # a comment
@array = qw(apple foo bar);
push(@array, 4);
%hash = (red => 'rot',
blue => 'blau');
print keys(%hash);
}
sub blah {
my $str = << ' EOS';
this is my string
and it's continuation
EOS
$str = "hello world";
$str = << " EOS";
this is my string
and it's continuation
EOS
}
&blah;
prg("test");
# Bracket closures in RegExp patterns (bug #364866)
qr{ ${var} aa{aa{a}a} aa*b?};
qr(aa(a(a(a(b|c)a)a)a)aa*b?);
s{aaa {aaa} a \x{A2} *b?}{aa};
s(aa(a(a(a(b|c)a)a)a)aa)(aa);
# Strings as scalar references (bug #348765)
$x = \'Reference of a String';
$y = \"Reference of a String";
# Variables that start with underscore (bug #355300)
$_variable
$_ # Reserved var.
for my $x ($hash->{arr}->@*) {
for my $k (keys $k->%*) {
...
}
}
diff --git a/autotests/folding/highlight.pony.fold b/autotests/folding/highlight.pony.fold
index d89d314..9e708ef 100644
--- a/autotests/folding/highlight.pony.fold
+++ b/autotests/folding/highlight.pony.fold
@@ -1,219 +1,219 @@
// Test file for Pony syntax highlighting, released under MIT License
primitive Red fun apply(): U32 => 0xFFFF0000
primitive Colours
fun black(): U32 => 0xFF000000
fun red(): U32 => 0xFFFF0000
primitive Black
primitive Blue
type Colour is (Black | Blue )
primitive ColourList
fun tag apply(): Array[Colour] =>
[Black; Blue]
for colour in ColourList().values() do
end
type EGLEvent is (U8, F32, F32)
(var code, var x, var y) = @getEvent[EGLEvent]()
primitive _XDisplayHandle
primitive _EGLDisplayHandle
let x_dpy = @XOpenDisplay[Pointer[_XDisplayHandle]](U32(0))
if x_dpy.is_null() then
env.out.print("XOpenDisplay failed")
end
let e_dpy = @eglGetDisplay[Pointer[_EGLDisplayHandle]](x_dpy)
if e_dpy.is_null() then
env.out.print("eglGetDisplay failed")
end
primitive _EGLConfigHandle
let a = Array[U16](8)
a.push(0x3040)
a.push(0b01011)
let config = Pointer[_EGLConfigHandle]
if @eglChooseConfig[U32](e_dpy, a, config, U32(1), Pointer[U32]) == 0 then
env.out.print("eglChooseConfig failed")
end
actor Main
new create(env: Env) =>
// The no of arguments
env.out.print(env.args.size().string())
for value in env.args.values() do
env.out.print(value)
end
// Access the arguments the first one will always be the the appication name
try env.out.print(env.args(0)?) end
actor Main
new create(env: Env) =>
var options = Options(env)
options
.add("output", "o", StringArgument)
env.out.print(options.has_argument())
for option in options do
match option
| ("output", var arg: String) => _outputFileName = arg.string()
| let err: ParseError =>
err.report(env.out)
env.out.print(
"""
pony-embed [OPTIONS]
--output name string output filename.
"""
)
end
end
use "ponytest"
actor Main is TestList
new create(env: Env) => PonyTest(env, this)
new make() => None
fun tag tests(test: PonyTest) =>
test(_TestAddition)
class iso _TestAddition is UnitTest
"""
Adding 2 numbers
"""
fun name(): String => "u32/add"
fun apply(h: TestHelper): TestResult =>
h.expect_eq[U32](2 + 2, 4)
fun tag log(msg: String, verbose: Bool = false)
be fail() =>
be assert_failed(msg: String) =>
fun tag assert_true(actual: Bool, msg: String = "") ?
fun tag expect_true(actual: Bool, msg: String = ""): Bool
fun tag expect_eq[A: (Equatable[A] #read & Stringable)]
(expect: A, actual: A, msg: String = ""): Bool
fun tag expect_eq[A: (Equatable[A] #unknown & Stringable)]
(expect: A, actual: A, msg: String = ""): Bool
fun add(other: A): A
fun sub(other: A): A
fun mul(other: A): A
fun div(other: A): A
fun mod(other: A): A
fun eq(other: A): Bool
fun ne(other: A): Bool
fun lt(other: A): Bool
fun le(other: A): Bool
fun ge(other: A): Bool
fun gt(other: A): Bool
fun shl(other: A): A
fun shr(other: A): A
fun op_and(other:A): A
fun op_or(other: A): A
fun op_xor(othr: A): A
class Test
fun alpha() =>
"""
"""
let dice: Array[U32] = [1; 2; 3
4
5
6
]
actor Main
fun foo(n:U32): {ref(U32): U32} =>
var s: Array[U32] = Array[U32].init(n, 1)
{ref(i:U32)(s): U32 =>
try
s(0) = s(0) + i
s(0)
- elseelse
+ else
0
end
}
new create(env:Env) =>
var f = foo(5)
env.out.print(f(10).string())
env.out.print(f(20).string())
/* nested /* commentary */ */
// single comment
class A
class _A
x'
x''
x'.string()
'\uaaaa'
'\Ubbbbbb'
'\xcc'
'\''
'\n'
"\uaaaaa"
"\Ubbbbbbb"
"\xccc"
"\""
"\n"
34.4
34.4e43
43e4
0x3040
0xaF
0b01
3_43_4
0x0_4
fun create(): U32 => 0
fun iso create(): U32 => 0
fun \\ abc \\ iso create(): U32 => 0
class \\ packet, blah \\ iso Xyz
if \\ likely \\ a then
end
a.endnormal
print();print()
/* syntactically false: */
class _aA
class _a
class a
0b2332
0b
0x
0xgf
0f00
3.
.3
3.e3
3_
3__43_4
''
'\u'
'\ua'
'\uaaa'
'\uaaaaa'
'\uyyyy'
"\u"
"\ua"
"\uaaa"
"\uyyyy"
a'a
class badType
print();
diff --git a/autotests/folding/highlight.prg.fold b/autotests/folding/highlight.prg.fold
index 9f03189..55ba4f4 100644
--- a/autotests/folding/highlight.prg.fold
+++ b/autotests/folding/highlight.prg.fold
@@ -1,71 +1,71 @@
// Test file to test kate's clipper highlighting
// kate: hl Clipper;
//BEGIN INCLUDES
#include
#include "logo.ch"
#define PRGVERSION "0.0.1"
//END
//BEGIN CODE
static ws, win
static driver := getDriver()
/* a multiline
comment
*/
function main( formName )
local form
local fileName
if empty(formName)
?? "Usage: ./form_ui &\n"
CANCEL
- elseelse
+ else
fileName := formName
endif
ws := UIWorkSpace()
form := UIForm( fileName )
win := form:parseFile()
// ?? valtype(win),chr(10)
if win == NIL
CANCEL
endif
win:show()
ws:run()
ws:quit()
return 0
/* Setting dialog */
function settingsDialog()
?? "TODO: Settings dialog&\n"
return
/* About dialog */
function aboutDialog()
local dlg := UIWindow("About", win, "aboutDlg", .F.)
local hl, lside, t, bb, bD
hl := UIHBox(,4,8)
lside := UIVBox()
lside:add(UIImage(eas_logo_mini,.T.))
hl:add(lside,.F.,.F.)
dlg:userSpace:add(hl,.T.,.T.)
t := UIVBox()
hl:add(t,.T.,.T.)
t:add(UILabel("License: GPL version 2 or later"))
bb := UIButtonBar()
t:add(bb)
bD := UIButton(win, "&Close", {|o,e| dlg:close() } )
bb:add( bD )
dlg:setFocus(bD)
dlg:setDefault(bD)
dlg:setPlacement( .T. )
dlg:show()
return
//END
diff --git a/autotests/folding/highlight.rb.fold b/autotests/folding/highlight.rb.fold
index 9008000..713aefc 100644
--- a/autotests/folding/highlight.rb.fold
+++ b/autotests/folding/highlight.rb.fold
@@ -1,573 +1,573 @@
# This file is a testcase for the highlighting of Ruby code
# It's not executable code, but a collection of code snippets
#
require 'Config'
require 'DO/Clients'
require 'DO/DBClients'
def CGI::escapeElement(string, *elements)
elements = elements[0] if elements[0].kind_of?(Array)
unless elements.empty?
string.gsub(/<\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?>/ni) do
CGI::escapeHTML($&)
end
- elseelse
+ else
string
end
end
case inputLine
when "debug"
dumpDebugInfo
dumpSymbols
when /p\s+(\w+)/
dumpVariable($1)
when "quit", "exit"
exit
- elseelse
+ else
print "Illegal command: #{inputLine}"
end
kind = case year #hi there
when 1850..1889 then "Blues"
when 1890..1909 then "Ragtime"
when 1910..1929 then "New Orleans Jazz"
when 1930..1939 then "Swing"
when 1940..1950 then "Bebop"
- else "Jazz"else "Jazz"
+ else "Jazz"
end
# URL-encode a string.
# url_encoded_string = CGI::escape("'Stop!' said Fred")
# # => "%27Stop%21%27+said+Fred"
def CGI::escape(string)
string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do
'%' + $1.unpack('H2' * $1.size).join('%').upcase
end.tr(' ', '+')
end
# Class ClientManager
#
# definition : Import, store and export the various data used by the application.
# This class is the sole interface between the application and the underlying database.
mon, day, year = $1, $2, $3 if /(\d\d)-(\d\d)-(\d\d)/
puts "a = #{a}" if fDebug
print total unless total == 0
while gets
next if /^#/ # Skip comments
parseLine unless /^$/ # Don't parse empty lines
end
if artist == "John Coltrane" #hi there
artist = "'Trane" #hi there
end unless nicknames == "no" #hi there
handle = if aSong.artist == "Gillespie" then #hi there
"Dizzy"
- elsif aSong.artist == "Parker" thenelsif aSong.artist == "Parker" then
+ elsif aSong.artist == "Parker" then
"Bird"
- else #hi thereelse #hi there
+ else #hi there
"unknown"
end
if aSong.artist == "Gillespie" then handle = "Dizzy"
-elsif aSong.artist == "Parker" then handle = "Bird"elsif aSong.artist == "Parker" then handle = "Bird"
-else handle = "unknown"else handle = "unknown"
+elsif aSong.artist == "Parker" then handle = "Bird"
+else handle = "unknown"
end #hi there
if aSong.artist == "Gillespie" then
handle = "Dizzy"
-elsif aSong.artist == "Parker" thenelsif aSong.artist == "Parker" then
+elsif aSong.artist == "Parker" then
handle = "Bird"
-elseelse
+else
handle = "unknown"
end
if aSong.artist == "Gillespie"
handle = "Dizzy"
-elsif aSong.artist == "Parker"elsif aSong.artist == "Parker"
+elsif aSong.artist == "Parker"
handle = "Bird"
-elseelse
+else
handle = "unknown"
end
case line
when /title=(.*)/
puts "Title is #$1"
when /track=(.*)/
puts "Track is #$1"
when /artist=(.*)/
puts "Artist is #$1"
end
case shape
when Square, Rectangle
# ...
when Circle
# ...
when Triangle
# ...
- elseelse
+ else
# ...
end
until playList.duration > 60 #hi there
playList.add(songList.pop)
end
3.times do
print "Ho! "
end
loop {
# block ...
}
songList.each do |aSong|
aSong.play
end
for aSong in songList
aSong.play
end
for i in ['fee', 'fi', 'fo', 'fum']
print i, " "
end
for i in 1..3
print i, " "
end
for i in File.open("ordinal").find_all { |l| l =~ /d$/}
print i.chomp, " "
end
class Periods
def each
yield "Classical"
yield "Jazz"
yield "Rock"
end
end
periods = Periods.new
for genre in periods
print genre, " "
end
while gets
next if /^\s*#/ # skip comments
break if /^END/ # stop at end
# substitute stuff in backticks and try again
redo if gsub!(/`(.*?)`/) { eval($1) }
# process line ...
end
i=0
loop do
i += 1
next if i < 3
print i
break if i > 4
end
for i in 1..100
print "Now at #{i}. Restart? "
retry if gets =~ /^y/i
end
def doUntil(cond)
yield
retry unless cond
end
i = 0
doUntil(i > 3) {
print i, " "
i += 1
}
def system_call
# ... code which throws SystemCallError
-rescue SystemCallErrorrescue SystemCallError
+rescue SystemCallError
$stderr.print "IO failed: " + $!
opFile.close
File.delete(opName)
raise
end
class ClientManager
# constructor
def initialize(dbase)
@dbClient = DBClient.new(dbase)
@clients = Clients.new
end
def prout(a, b, xy="jj") 24 end
###############################################################
#
# CLIENTS SECTION
#
###############################################################
# update the clients object by retrieving the related data from the database
# returns the number of clients
def refreshClients
@clients.clean
unless @sqlQuery.nil? then
@sqlQuery.selectClient.each do |row|
@clients.addClient(row[0],row[1],row[2],row[3],row[4],row[5], row[6], row[7], row[8])
end
- elseelse
+ else
puts "SqlQuery wasn't created : cannot read data from database"
end
return @clients.length
end
# insert a client in the database and refreshes the local clients object
# we assume that none of the arguments is null
# we assume that the client, identified by raison_sociale doesn't already exists
def addClient(raison_sociale, division, departement, adresse, cp, ville, nom_contact, tel_contact)
id = "0"
unless @sqlQuery.nil? then
id = @sqlQuery.insertClient(raison_sociale, division, departement, adresse, cp, ville, nom_contact,tel_contact)
- elseelse
+ else
puts "SqlQuery wasn't created : database update cannot be performed"
end
@clients.addClient(id, raison_sociale, division, departement, adresse, cp, ville, nom_contact, tel_contact) # synchronize local object with DB
end
# deletes a client from the database and updates the local Clients object accordingly
def delClient(nomclient_brut)
raison_sociale, div, dep = Clients.getIdentifiers(nomclient_brut)
listeContratsExp, listeContratsSup, listeContratsProd, listePropositionsExp, listePropositionsSup = []
listeContratsExp = @contratsExpertise.getContratsFromClient(nomclient_brut)
listeContratsSup = @contratsSupport.getContratsFromClient(nomclient_brut)
listeContratsProd = @contratsProduits.getContratsFromClient(nomclient_brut)
listePropositionsExp = @propositionsExpertise.getPropositionsFromClient(nomclient_brut)
listePropositionsSup = @propositionsSupport.getPropositionsFromClient(nomclient_brut)
unless @sqlQuery.nil? then
@sqlQuery.deleteClient(raison_sociale, div, dep)
@sqlQuery.deleteContracts(Config::EXPERTISE,listeContratsExp)
@sqlQuery.deleteContracts(Config::SUPPORT,listeContratsSup)
@sqlQuery.deleteContracts(Config::PRODUIT,listeContratsProd)
@sqlQuery.deletePropositions(Config::EXPERTISE,listePropositionsExp)
@sqlQuery.deletePropositions(Config::SUPPORT,listePropositionsSup)
- elseelse
+ else
puts "SqlQuery wasn't created : database update cannot be performed"
end
@clients.delClient(raison_sociale,div,dep)
@contratsExpertise.deleteContracts(listeContratsExp)
@contratsSupport.deleteContracts(listeContratsSup)
@contratsProduits.deleteContracts(listeContratsProd)
@propositionsExpertise.deletePropositions(listePropositionsExp)
@propositionsSupport.deletePropositions(listePropositionsSup)
end
end
# Mixin module for HTML version 3 generation methods.
module Html3 # :nodoc:
# The DOCTYPE declaration for this version of HTML
def doctype
%||
end
# Initialise the HTML generation methods for this version.
def element_init
extend TagMaker
methods = ""
# - -
for element in %w[ A TT I B U STRIKE BIG SMALL SUB SUP EM STRONG
DFN CODE SAMP KBD VAR CITE FONT ADDRESS DIV center MAP
APPLET PRE XMP LISTING DL OL UL DIR MENU SELECT table TITLE
STYLE SCRIPT H1 H2 H3 H4 H5 H6 TEXTAREA FORM BLOCKQUOTE
CAPTION ]
methods += <<-BEGIN + nn_element_def(element) + <<-END
def #{element.downcase}(attributes = {})
BEGIN
end
END
end
# - O EMPTY
for element in %w[ IMG BASE BASEFONT BR AREA LINK PARAM HR INPUT
ISINDEX META ]
methods += <<-BEGIN + nOE_element_def(element) + <<-END
def #{element.downcase}(attributes = {})
BEGIN
end
END
end
# O O or - O
for element in %w[ HTML HEAD BODY P PLAINTEXT DT DD LI OPTION tr
th td ]
methods += <<-BEGIN + nO_element_def(element) + <<-END
def #{element.downcase}(attributes = {})
BEGIN
end
END
end
eval(methods)
end
end
# following snippet from Webrick's log.rb
# notice the erronous handling of the query method is_a?
def format(arg)
str = if arg.is_a?(Exception)
"#{arg.class}: #{arg.message}\n\t" <<
arg.backtrace.join("\n\t") << "\n"
- elsif arg.respond_to?(:to_str)elsif arg.respond_to?(:to_str)
+ elsif arg.respond_to?(:to_str)
arg.to_str
- elseelse
+ else
arg.inspect
end
end
# following snippet from Webrick's httputils.rb
# Splitting regexps on several lines might be bad form,
# but not illegal in Ruby.
# This should probably be supported in the highlighting
def split_header_value(str)
str.scan(/((?:"(?:\\.|[^"])+?"|[^",]+)+)
(?:,\s*|\Z)/xn).collect{|v| v[0] }
end
# snippet from Net::Telnet
string.gsub(/#{IAC}(
[#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]|
[#{DO}#{DONT}#{WILL}#{WONT}]
[#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{OPT_EXOPL}]|
#{SB}[^#{IAC}]*#{IAC}#{SE}
)/xno)
# following snippet from Webrick's httpresponse.rb
# the HEREDOC is not recognized as such
@body << <<-_end_of_html_
#{HTMLUtils::escape(@reason_phrase)}
#{HTMLUtils::escape(@reason_phrase)}
#{HTMLUtils::escape(ex.message)}
_end_of_html_
# snippet from Webrick's httpproxy.rb
# here we should make sure that the symbol definition ':' doesn't override
# the module operator '::'
Net::HTTP::version_1_2 if RUBY_VERSION < "1.7"
# snippet from Webrick's cookie.rb
# the beginning of the regexp is erronously highlighted like an operator
key, val = x.split(/=/,2)
# the following are division operators
# it's a bit tricky to keep the operator apart from the regexp
result = 8 / 4
result /= divisor
# 2008-06-01 regexp and division operator syntax has been fixed:
result = 8/4 # division
result = 8/foo # division
result = /8/ # regexp
result = 8//4/ # division and regexp
10/10 # division
10/ 10 # division
10 /10 # division
10 / 10 # division
foo/10 # division
foo/ 10 # division
foo /10/ # regexp
foo / 10 # division
foo/10/10 # both division
total/count/2 # both division
total/(count/2) # both division
@foo/10 # division
@foo /10 # division
"hello"/10 # division
"hello" / 10 # division
/regexp//10 # division
/regexp/ / 10 # division
Math::PI/10 # division
Math::foo /rx/ # regexp
# 2008-06-05 similar fix for modulo operator:
10%4 # modulo
10 %4 # modulo
10% 4 # modulo
10 % 4 # modulo
foo%4 # modulo
# foo %4 # illegal %string
foo% 4 # modulo
foo % 4 # modulo
foo % (4) # modulo
foo %(4) # %string
foo %q(4) # %string
foo %Q(4) # %string
foo %%4% # %string
foo = %|blah| # GDL input
foo % %|blah| # modulo and GDL
# mix in any way you want
result = 10//regexp//20/foo//regexp//20
# test cases for general delimited input
# quoted strings
%Q|this is a string|
%Q{this is a string}
%Q(this is a string)
%Q>
%Q[this is a string]
%|also a string|
%{also a string}
%(also a string)
%>
%[also a string]
# apostrophed strings
%q|apostrophed|
%q{apostrophed}
%q(apostrophed)
%q>
%q[apostrophed]
# regular expressions
%r{expression}
%r(expression)
%r>
%r[expression]
%r|expression|
# shell commands
%x{ls -l}
%x(ls -l)
%x>
%x[ls -l]
# sometimes it's useful to have the command on multiple lines
%x{ls -l |
grep test }
# alternative syntax
`ls -l`
`echo ' '`
# token array
%w{one two three}
%w(one two three)
%w>
%w[one two three]
# snippet from Net::IMAP
# I object to putting String, Integer and Array into kernel methods.
# While these classes are builtin in Ruby, this is an implementation detail
# that should not be exposed to the user.
# If we want to handle all std-lib classes, fine. But then they should be in their
# own std-lib keyword category.
def send_data(data)
case data
when nil
put_string("NIL")
when String
send_string_data(data)
when Integer
send_number_data(data)
when Array
send_list_data(data)
when Time
send_time_data(data)
when Symbol
send_symbol_data(data)
- elseelse
+ else
data.send_data(self)
end
end
# snippet from Net::POP
# class names can have numbers in them as long as they don't begin with numbers
# Ruby doesn't internally really make much of a difference between a class name and a constant
# class aliases
POP = POP3
POPSession = POP3
POP3Session = POP3
# "member access"
POP::Session.COUNT.attribute.calc_with(2){ |arg| puts arg }
# snippet from Net::SMTP
# This breaks the code folding. I think we would need to
# handle the '\' that continues the statement to the next line
# in some way to make these kind of things not break something.
raise ArgumentError, 'both user and secret are required'\
unless user and secret
# string escapes must detect escaping the escape char
str = "\\"
str = "\\\\"
# this is not part of the string
%x{echo \\\}\\} # prints \}\
# this is not part of the command
# these are all symbols
:abc
:abc!
:abc?
:abc=
:[]
:[]=
:@abc
:@@abc
:$abc
# squiggly HEREDOC
<<~HEREDOC
Hello!!
HEREDOC
# HEREDOC with backticks
<<`HEREDOC`
echo "hello"
HEREDOC
# do not highlight HEREDOC markers after the "class" keyword
# (singleton class definition) (bug: #358273)
class <end
singleton_class = ( class <end )
# highlight regular expressions after ": " (bug: #361875)
get 'files/:slug/:filename', to: 'files#download', slug: /^[a-z]+$/, filename: %r|^[/\s]+$|
@@hello!: /regexp/
[]=: %r!regexp!
diff --git a/autotests/folding/highlight.spec.fold b/autotests/folding/highlight.spec.fold
index 6ed00cf..4ecb442 100644
--- a/autotests/folding/highlight.spec.fold
+++ b/autotests/folding/highlight.spec.fold
@@ -1,212 +1,212 @@
# Test file for rpmspec.xml
# Comments start with a # in column="0":
# Some comment
# When they don't start in column="0", that they are recognized as comments, but with an alert:
# This is a bad comment.
# RPM spec says clear that comments must start at the begin of the line. However, in practice
# the RPM software is more permissive, depending on the context. But for our syntax highlighting,
# we give, while recognizing the as comment, at least a little alert. Comments should not contain
# the character % (which is marked as warning), but 2 of them are okay: %%. TODO is higlighted.
# A spec file starts with "Normal" context. Here, you can specify values for some tags:
Name: kradioripper-unstable # Note that here in no comment possible!
Name: name only _one_ word allowed
Name: %macro no further syntax check after macro!
# Some tags support only _one_ word as value
Version: 0.4test5 up-from-the-space-this-is-an-error
# Some tag can have parameters: Any char in paranthesis:
Summary: Recorder for internet radios (based on Streamripper)
Summary(de.UTF-8): Aufnahmeprogramm für Internetradios (basiert auf Streamripper)
# requiere free text:
License: License 1 2 3
# requiere a well defines value:
Requires( / ( = ): Some, value()
# new type "switch" accepts: yes, no, 0, 1
AutoReq: yes
AutoReq: yes invalid
AutoReq: %macro no further syntax check after macro!
AutoReq: no
AutoReq: 0
AutoReq: 1
# requiere a number:
Epoch: 123123
Epoch: 123123 invalid
Epoch: %macro no further syntax check afer macro!
# If tags are used that are not known, they are not highlighted:
Invalidtag: Some value
Invalid content in this section (only tags are allowed)
# You can use conditions in specs (highlighted with region markers):
%if 0%{?mandriva_version}
# numbers and strings are distingished: string:
%if lsdksfj
# number:
%if 23472398
# string:
%if lksdjfsl72939
# invalid:
%if 92437lsdkfjdsl
# valid:
%if "lsdfj %ksdf(sdfs) 3489"
Release: %mkrel 1.2
-%else %else
+%else
Release: 0
%endif
# requiere a well defined value:
%ifos fixed_value
# You must use these special macros (%%if etc.) always at the start of the line - if not,
# that's bad but not an arror. You must also always use the specified form. Everything else is an
# error:
%if
something %if
%{if}
%if(some options)
# However, this are different macros and therefore correct:
%ifx
%{ifx}
%ifx(some options)
# the \ is escaped in the line. At the end of the line it escapes the line break:
echo This is \" a text \\ and here\
it continues.
%define name value
%define invalid_näme value
%define macroname multi\
line content with references like %0 %* %# %{-f} %{-f*} %1 %2 and so on
%global name value
%global invalid_näme value
%undefine name
%undefine name too-many-parameters
# This special comment is treated and highlighted like a tag:
# norootforbuild
# It can't have parameters, so every following non-whitespace character is not good:
# norootforbuild DONT WRITE ANYTHING HERE!
# wrong spacing is also recognized:
# norootforbuild
# and also an indeet is not fine for norootforbuild:
# norootforbuild
# This following "Conflicts" tag will be removed by set-version.sh,
# if it is a "kradioripper" release (and not a "kradioripper-unstable" release)...
Conflicts: kradioripper
%description
# Here, a new section starts. It contains a value for the RPM field "description" and is therefor
# colored like values:
A KDE program for ripping internet radios. Based on StreamRipper.
# A section start can have parameters:
%description -l de.UTF-8
Ein KDE-Aufnahmeprogramm für Internetradios. Basiert auf StreamRipper.
# These sections starts are errors:
%description not at the first line
%{description} wrong form
%description(no options allowed, only parameters!)
%prep
# This starts a section that defines the commands to prepare the build.
# q means quit. n sets the directory:
%setup -q -n kradioripper
echo Test
# Macros can have different forms: Valid:
%abc
%abcÄndOfMacro
%abc(def)EndOfMacro
%{abc}EndOfMacro
%{something but no single %}EndOfMacro
%{abc:def}EndOfMacro
%(abc)
# Invalid:
%ÄInvalidChar
%
%)
%}
# You can use macros inside of macro calls: Fine:
%{something %but no %{sin%(fine)gle} }EndOfMacro
# Bad:
%{No closing paranthesis (No syntax highlightig for this error available)
%build
cmake ./ -DCMAKE_INSTALL_PREFIX=%{_prefix}
%__make %{?jobs:-j %jobs}
%install
%if 0%{?suse_version}
%makeinstall
%suse_update_desktop_file kradioripper
%endif
%if 0%{?fedora_version} || 0%{?rhel_version} || 0%{?centos_version}
make install DESTDIR=%{buildroot}
desktop-file-install --delete-original --vendor fedora --dir=%{buildroot}/%{_datadir}/applications/kde4 %{buildroot}/%{_datadir}/applications/kde4/kradioripper.desktop
%endif
%if 0%{?mandriva_version}
%makeinstall_std
%endif
%clean
rm -rf "%{buildroot}"
%files
%defattr(-,root,root)
%if 0%{?fedora_version} || 0%{?rhel_version} || 0%{?centos_version}
%{_datadir}/applications/kde4/fedora-kradioripper.desktop
-%else %else
+%else
%{_datadir}/applications/kde4/kradioripper.desktop
%endif
%{_bindir}/kradioripper
%{_datadir}/locale/*/LC_MESSAGES/kradioripper.mo
%if 0%{?mandriva_version}
# TODO The %%doc macro is actually broken for mandriva 2009 in build service...
%dir %{_datadir}/apps/kradioripper
%{_datadir}/apps/kradioripper/*
-%else %else
+%else
%doc COPYING LICENSE LICENSE.GPL2 LICENSE.GPL3 NEWS WARRANTY
%dir %{_datadir}/kde4/apps/kradioripper
%{_datadir}/kde4/apps/kradioripper/*
%endif
%changelog
* Sun May 04 2008 email@email.com
- some text
- some text
in two lines
- some text
in two lines
+ with subtext
- and more subtext
in two lines
* Tue Apr 24 2007 Name
- text
* When the star isn't at column 0, than it doesn't indicate
a new date
* Wen Sep 08 2003 Wrong weekday
* Mon Mai 08 2003 Wrong month
* Mon Sep 0 2003 bad day
* Mon Sep 8 2003 good day
* Mon Sep 08 2003 good day
* Mon Sep 32 2003 bad day
* Mon Sep 08 03 bad year
* Mon Sep 08 2003 Name
# When using macros, the error check is disabled:
* %myDataMacro Title of the entry
- Text
- can
- be
- indeeded
- without
- problems
diff --git a/autotests/folding/highlight.t2t.fold b/autotests/folding/highlight.t2t.fold
index 428f204..e733d68 100644
--- a/autotests/folding/highlight.t2t.fold
+++ b/autotests/folding/highlight.t2t.fold
@@ -1,90 +1,90 @@
txt2tags sample
%!--includeconf: config.t2t
% disabled here because there is no external file
%!preproc: 'JUST A TEST' ' '
%!postproc: '(?i)()' ' shots\1'
%!--include: menu.t2t
-= Title 1 == Title 1 =
+= Title 1 =
-== My Subtitle 1 ==[some definition]== My Subtitle 1 ==[some definition]
+== My Subtitle 1 ==[some definition]
Some examples:
- A paragraph with **bold**, //italic// and --strike--.
- You can even __underline your docs__!
- And use **//bold and italic//**
- or //**italic and bold**//
Here is a nice pic: [img/t2tpowered.png].
- And a [link to a cool website http://txt2tags.sf.net]!
- A table :
|| Name | Age | Gender |
| John | 33 | Male |
| Mary | 19 | Female |
``` A verbatim line
And it's working for ``special code`` like this.
```
Unfortunately I can't color this verbatim content yet.
```
-== My Subtitle 2 ==== My Subtitle 2 ==
+== My Subtitle 2 ==
Lorem ipsum etc
Lorem ipsum etc Lorem ipsum etc
- Test d'écriture avec des accents à la française. Ça marche ou pas ?
-== My Subtitle 3 ==== My Subtitle 3 ==
+== My Subtitle 3 ==
Lorem ipsum etc
Lorem ipsum etc
Here is a direct link: http://kde.org
- Another boring part...
-=== My Subsubtitle 1 ====== My Subsubtitle 1 ===
+=== My Subsubtitle 1 ===
//It's a level 3 header//
- list 1
- list 2
- list 2b
- list 3
-=== My Subsubtitle 2 ====== My Subsubtitle 2 ===
+=== My Subsubtitle 2 ===
//It's another level 3 header//
+ ordered list 1
+ list 2
+ list 2B
+ list 2C
+ list 3
-== My Subtitle 4 ==== My Subtitle 4 ==
+== My Subtitle 4 ==
nothing to say here...
diff --git a/autotests/folding/highlight.y.fold b/autotests/folding/highlight.y.fold
index d977948..dfae62c 100644
--- a/autotests/folding/highlight.y.fold
+++ b/autotests/folding/highlight.y.fold
@@ -1,95 +1,95 @@
/* Yacc / Bison hl test file.
* It won't compile :-) Sure !
*/
%{
#include
using namespace std;
extern KateParser *parser;
%}
%locations
%union {
int int_val;
double double_val;
bool bool_val;
char *string_val;
char *ident_val;
struct var *v;
void *ptr;
}
%token TOK_NOT_EQUAL "!="
%token TOK_LESSER_E "<="
%token TOK_GREATER_E ">="
%token TOK_EQUAL_2 "==" //comment
%token
PERCENT_DEBUG "%debug"
PERCENT_DEFAULT_PREC "%default-prec"
PERCENT_DEFINE "%define"
;
%type type type_proc
%code top {
#define _GNU_SOURCE
#include
int val;
}
%destructor { free ($$); printf ("%d", @$.first_line); } <*>
%lex-param {scanner_mode *mode};
%parse-param {int *nastiness} {int *randomness}
%initial-action {
@$.initialize (file_name);
};
-%%%%
+%%
prog: KW_PROGRAM ident { parser->start($2); } prog_beg_glob_decl instructions { parser->endproc(0); } dev_procedures KW_ENDP ;
number: integer_number
| TOK_DOUBLE
{
$$ = new var;
$$->type = KW_REEL;
$$->cl = var::LITTERAL;
$$->real = $1;
};
words:
%empty
| words word
;
%type word;
%printer { fprintf (yyo, "%s", word_string ($$)); } ;
word:
%?{ boom(1); }
| "hello" { $$ = hello; }
| "bye" { $$ = bye; }
;
foo: { $$ = 0 }
| number { $$ = $1 | $2; }
| hello { $$ = $1 | $3; } // without a comma
hello:
gram1 { $$ = "hi" };
| gram2
;;
-%%%%
+%%
#include
int main(void)
{
puts("Hello, World!");
return 0;
}
// ALERT NOTE
diff --git a/autotests/folding/test.desktop.fold b/autotests/folding/test.desktop.fold
index 77db817..7a204f4 100644
--- a/autotests/folding/test.desktop.fold
+++ b/autotests/folding/test.desktop.fold
@@ -1,19 +1,33 @@
# test file for .dekstop syntax highlighting
-[Desktop Entry][Desktop Entry]
+[Desktop Entry]
GenericName=Text Editor
GenericName[ar]=محرّر نصوص
Name=KWrite
Name[ar]=كاتبك
Comment=KDE Text Editor
Comment[ar]=محرّر نصوص لكدي
MimeType=text/plain;
Exec=kwrite %U
StartupNotify=true
Icon=kwrite
X-DocPath=kwrite/index.html
Type=Application
Terminal=false
InitialPreference=8
X-DBUS-StartupType=Multi
X-DBUS-ServiceName=org.kde.kwrite
Categories=Qt;KDE;Utility;TextEditor;
+Actions=new-window;new-tab;
+
+# test folding: the header should not be
+# part of the previous region.
+# NOTE: this options in Exec don't exist.
+[Desktop Action new-window]
+Name=New Window
+Exec=kwrite --new-window
+Icon=kwrite
+
+[Desktop Action new-tab]
+Name=New Tab
+Exec=kwrite --new-tab
+Icon=kwrite
diff --git a/autotests/folding/test.ini.fold b/autotests/folding/test.ini.fold
index 27d80c8..2353cb1 100644
--- a/autotests/folding/test.ini.fold
+++ b/autotests/folding/test.ini.fold
@@ -1,18 +1,18 @@
; comment
; comment with ### alerts
# alternative comments
-[Empty section][Empty section]
+[Empty section]
-[Section 2][Section 2]
+[Section 2]
Key1=String Value
Key2=42
Key3=3.14
Key\SubKey=True
-[Section 3][Section 3]
+[Section 3]
; = in values are fine
; inline comments are not supported, ;/# are part of the value
key4 = foo = True; bar = False
key4b = abcd#1234!
key5/subkey = "foo\nbar"
diff --git a/autotests/folding/usr.bin.apparmor-profile-test.fold b/autotests/folding/usr.bin.apparmor-profile-test.fold
index 64deede..d44d9b0 100644
--- a/autotests/folding/usr.bin.apparmor-profile-test.fold
+++ b/autotests/folding/usr.bin.apparmor-profile-test.fold
@@ -1,270 +1,270 @@
# Sample AppArmor Profile.
# License: Public Domain
# NOTE: This profile is not fully functional, since
# it is designed to test the syntax highlighting.
include
# Variable assignment
@{FOO_LIB}=/usr/lib{,32,64}/foo
@{USER_DIR}
= @{HOME}/Public @{HOME}/Desktop #No-Comment
@{USER_DIR} += @{HOME}/Hello \
deny owner #No-comment aa#aa
${BOOL} = true
# Alias
alias /usr/ -> /mnt/usr/,
# Profile for /usr/bin/foo
profile foo /usr/bin/foo flags=(attach_disconnected enforce) {
#include
#include
#include"/etc/apparmor.d/abstractions/ubuntu-konsole"
include "/etc/apparmor.d/abstractions/openssl"
include if exists
include #include
/some/file mr, #include /bin/true Px,
# File rules
/{,**/} r,
owner /{home,media,mnt,srv,net}/** r,
owner @{USER_DIR}/** rw,
audit deny owner /**/* mx,
/**.[tT][xX][tT] r, # txt
owner file @{HOME}/.local/share/foo/{,**} rwkl,
owner @{HOME}/.config/*.[a-zA-Z0-9]* rwk,
"/usr/share/**" r,
"/var/lib/flatpak/exports/share/**" r,
"/var/lib/{spaces in
string,hello}/a[^ a]a/**" r,
allow file /etc/nsswitch.conf r,
allow /etc/fstab r,
deny /etc/xdg/{autostart,systemd}/** r,
deny /boot/** rwlkmx,
owner @{PROC}/@{pid}/{cmdline,mountinfo,mounts,stat,status,vmstat} r,
/sys/devices/**/uevent r,
@{FOO_LIB}/{@{multiarch},64}/** mr,
/usr/bin/foo ixr,
/usr/bin/dolphin pUx,
/usr/bin/* Pixr,
/usr/bin/khelpcenter Cx -> sanitized_helper,
/usr/bin/helloworld cxr ->
hello_world,
# Dbus rules
dbus (send) #No-Comment
bus=system
path=/org/freedesktop/NetworkManager
interface=org.freedesktop.DBus.Introspectable
peer=(name=org.freedesktop.NetworkManager label=unconfined),
dbus (send receive)
bus=system
path=/org/freedesktop/NetworkManager
interface=org.freedesktop.NetworkManager
member={Introspect,state}
peer=(name=(org.freedesktop.NetworkManager|org.freedesktop.DBus)),
dbus (send)
bus=session
path=/org/gnome/GConf/Database/*
member={AddMatch,AddNotify,AllEntries,LookupExtended,RemoveNotify},
dbus (bind)
bus=system
name=org.bluez,
# Signal rules
signal (send) set=(term) peer="/usr/lib/hello/world// foo helper",
signal (send, receive) set=(int exists rtmin+8) peer=/usr/lib/hello/world//foo-helper,
# Child profile
profile hello_world {
# File rules (three different ways)
file /usr/lib{,32,64}/helloworld/**.so mr,
/usr/lib{,32,64}/helloworld/** r,
rk /usr/lib{,32,64}/helloworld/hello,file,
# Link rules (two ways)
l /foo1 -> /bar,
link /foo2 -> bar,
link /foo3 to bar,
link subset /link* -> /**,
# Network rules
network inet6 tcp,
network netlink dgram,
network bluetooth,
network unspec dgram,
# Capability rules
capability dac_override,
capability sys_admin,
capability sys_chroot,
# Mount rules
mount options=(rw bind remount nodev noexec) vfstype=ecryptfs /home/*/.helloworld/ -> /home/*/helloworld/,
mount options in (rw, bind) / -> /run/hellowordd/*.mnt,
mount option=read-only fstype=btrfs /dev/sd[a-z][1-9]* -> /media/*/*,
umount /home/*/helloworld/,
# Pivot Root rules
pivot_root oldroot=/mnt/root/old/ /mnt/root/,
pivot_root /mnt/root/,
# Ptrace rules
ptrace (trace) peer=unconfined,
ptrace (read, trace, tracedby) peer=/usr/lib/hello/helloword,
# Unix rules
unix (connect receive send) type=(stream) peer=(addr=@/tmp/ibus/dbus-*,label=unconfined),
unix (send,receive) type=(stream) protocol=0 peer=(addr=none),
unix peer=(label=@{profile_name},addr=@helloworld),
# Rlimit rule
set rlimit data <= 100M,
set rlimit nproc <= 10,
set rlimit memlock <= 2GB,
set rlimit rss <= infinity,
# Change Profile rules
change_profile unsafe /** -> [^u/]**,
change_profile unsafe /** -> {u,un,unc,unco,uncon,unconf,unconfi,unconfin,unconfine},
change_profile /bin/bash ->
new_profile//hat,
}
# Hat
^foo-helper\/ {
network unix stream,
unix stream,
/usr/hi\"esc\x23esc\032es\477esc\*es\{esc\ rw r, # Escape expressions
# Text after a variable is highlighted as path
file /my/path r,
@{FOO_LIB}file r,
@{FOO_LIB}#my/path r, #Comment
@{FOO_LIB}ñ* r,
unix (/path\t{aa}*,*a @{var}*path,* @{var},*),
}
}
# Syntax Error
/usr/bin/error (complain, audit) {
file #include /hello r,
# Error: Variable open or with characters not allowed
@{var
@{sdf&s}
# Error: Open brackets
/{hello{ab,cd}world kr,
/{abc{abc kr,
/[abc kr,
/(abc kr,
# Error: Empty brackets
/hello[]hello{}hello()he kr,
# Comments not allowed
dbus (send) #No comment
path=/org/hello
#No comment
interface=org.hello #No comment
peer=(name=org.hello #No comment
label=unconfined), #Comment
@{VARIABLE} = val1 val2 val3 #No comment
# Error: Open rule
/home/*/file rw
- capability dac_overridecapability dac_override
+ capability dac_override
deny file /etc/fstab w
audit network ieee802154,
dbus (receive
- unix stream,unix stream,
+ unix stream,
unix stream,
}
profile other_tests {
# set rlimit
set rlimit nice <= 3,
rlimit nice <= 3, # Without "set"
set #comment
rlimit
nice <= 3,
# "remount" keyword
mount remount
remount,
remount remount
remount,
dbus remount
- remount,remount,
+ remount,
unix remount
- remount,remount,
+ remount,
# "unix" keyword
network unix
unix,
ptrace unix
- unix,unix,
+ unix,
unix unix
- unix,unix,
+ unix,
# Transition rules
/usr/bin/foo cx -> hello*,
/usr/bin/foo Cx -> path/,
/usr/bin/foo cx -> ab[ad/]hello,
/usr/bin/foo Cx -> ab[cd/]a[ad/]hello/path,
/usr/bin/foo Cx -> ab[hello/path,
/usr/bin/foo cx -> "hello*",
/usr/bin/foo Cx -> "path/",
/usr/bin/foo cx -> "ab[ad/]hello",
/usr/bin/foo Cx -> "ab[cd/]a[ad/]hello/path",
/usr/bin/foo Cx -> "ab[hello/path",
/usr/bin/foo cx -> holas//hello/sa,
/usr/bin/foo cx -> df///dd//hat,
/usr/bin/foo cx -> holas,#sd\323fsdf,
# Access modes
/hello/lib/foo rwklms, # s invalid
/hello/lib/foo rwmaix, # w & a incompatible
/hello/lib/foo kalmw,
/hello/lib/foo wa,
# OK
/hello/lib/foo rrwrwwrwrw,
/hello/lib/foo ixixix,
# Incompatible exec permissions
ixixux, uxuxUxux, ixixixPixix, ixixpx uxuxuxPuxux, UxUxcUxUx,
pixpixcixix, cxcxcxix, pixpixpux pixpixix xxix xxpux ixixx puxpuxx,
Cuxcux Pixpix, puxpUx puxPUx xxpix xxcx,
# Test valid permissions
r w a k l m l x ix ux Ux px Px cx Cx ,
pix Pix cix Cix pux Pux cux Cux pUx PUx cUx CUx,
rwklmx raklmx,
r rw rwk rwkl rwklm,
rwlmix rwlmUx rwlmPx rwlmcx rwlmPUx,
rwixixixkl rwUxUxUxkl rwuxuxuxk rwpxpxpxk rwPxPxkl rwcxcxlm rwCxCxk,
rwpixpixk rwPixPixkl wrpuxpuxk rwpUxpUxk rwcixcixcixml rwCixCixk rwCuxCuxk rwCUxCUxl,
# Profile name
profile holas { ... }
profile { ... }
profile /path { ... }
profile holas/abc { ... }
profile holas\/abc { ... }
profile
#holas { ... }
profile flags=(complain)#asd { ... }
profile flags flags=(complain) { ... }
profile flags(complain) { ... }
}
diff --git a/autotests/html/test.desktop.html b/autotests/html/test.desktop.html
index 66cdb27..0a2acc2 100644
--- a/autotests/html/test.desktop.html
+++ b/autotests/html/test.desktop.html
@@ -1,26 +1,40 @@
test.desktop
# test file for .dekstop syntax highlighting
[Desktop Entry]
GenericName=Text Editor
GenericName[ar]=محرّر نصوص
Name=KWrite
Name[ar]=كاتبك
Comment=KDE Text Editor
Comment[ar]=محرّر نصوص لكدي
MimeType=text/plain;
Exec=kwrite %U
StartupNotify=true
Icon=kwrite
X-DocPath=kwrite/index.html
Type=Application
Terminal=false
InitialPreference=8
X-DBUS-StartupType=Multi
X-DBUS-ServiceName=org.kde.kwrite
Categories=Qt;KDE;Utility;TextEditor;
+Actions=new-window;new-tab;
+
+# test folding: the header should not be
+# part of the previous region.
+# NOTE: this options in Exec don't exist.
+[Desktop Action new-window]
+Name=New Window
+Exec=kwrite --new-window
+Icon=kwrite
+
+[Desktop Action new-tab]
+Name=New Tab
+Exec=kwrite --new-tab
+Icon=kwrite
diff --git a/autotests/input/test.desktop b/autotests/input/test.desktop
index f3edd78..9212aaf 100644
--- a/autotests/input/test.desktop
+++ b/autotests/input/test.desktop
@@ -1,19 +1,33 @@
# test file for .dekstop syntax highlighting
[Desktop Entry]
GenericName=Text Editor
GenericName[ar]=محرّر نصوص
Name=KWrite
Name[ar]=كاتبك
Comment=KDE Text Editor
Comment[ar]=محرّر نصوص لكدي
MimeType=text/plain;
Exec=kwrite %U
StartupNotify=true
Icon=kwrite
X-DocPath=kwrite/index.html
Type=Application
Terminal=false
InitialPreference=8
X-DBUS-StartupType=Multi
X-DBUS-ServiceName=org.kde.kwrite
Categories=Qt;KDE;Utility;TextEditor;
+Actions=new-window;new-tab;
+
+# test folding: the header should not be
+# part of the previous region.
+# NOTE: this options in Exec don't exist.
+[Desktop Action new-window]
+Name=New Window
+Exec=kwrite --new-window
+Icon=kwrite
+
+[Desktop Action new-tab]
+Name=New Tab
+Exec=kwrite --new-tab
+Icon=kwrite
diff --git a/autotests/reference/test.desktop.ref b/autotests/reference/test.desktop.ref
index 12ca73f..47b5c58 100644
--- a/autotests/reference/test.desktop.ref
+++ b/autotests/reference/test.desktop.ref
@@ -1,19 +1,33 @@
# test file for .dekstop syntax highlighting
GenericName=Text Editor
GenericName[ar]=محرّر نصوص
Name=KWrite
Name[ar]=كاتبك
Comment=KDE Text Editor
Comment[ar]=محرّر نصوص لكدي
MimeType=text/plain;
Exec=kwrite %U
StartupNotify=true
Icon=kwrite
X-DocPath=kwrite/index.html
Type=Application
Terminal=false
InitialPreference=8
X-DBUS-StartupType=Multi
X-DBUS-ServiceName=org.kde.kwrite
Categories=Qt;KDE;Utility;TextEditor;
+Actions=new-window;new-tab;
+
+# test folding: the header should not be
+# part of the previous region.
+# NOTE: this options in Exec don't exist.
+[Desktop Action new-window]
+Name=New Window
+Exec=kwrite --new-window
+Icon=kwrite
+
+
+Name=New Tab
+Exec=kwrite --new-tab
+Icon=kwrite
diff --git a/src/lib/abstracthighlighter.cpp b/src/lib/abstracthighlighter.cpp
index 159fb52..fd6a9e9 100644
--- a/src/lib/abstracthighlighter.cpp
+++ b/src/lib/abstracthighlighter.cpp
@@ -1,359 +1,366 @@
/*
Copyright (C) 2016 Volker Krause
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "abstracthighlighter.h"
#include "abstracthighlighter_p.h"
#include "context_p.h"
#include "definition_p.h"
#include "foldingregion.h"
#include "format.h"
#include "repository.h"
#include "rule_p.h"
#include "state.h"
#include "state_p.h"
#include "ksyntaxhighlighting_logging.h"
#include "theme.h"
using namespace KSyntaxHighlighting;
AbstractHighlighterPrivate::AbstractHighlighterPrivate()
{
}
AbstractHighlighterPrivate::~AbstractHighlighterPrivate()
{
}
void AbstractHighlighterPrivate::ensureDefinitionLoaded()
{
auto defData = DefinitionData::get(m_definition);
if (Q_UNLIKELY(!m_definition.isValid() && defData->repo && !m_definition.name().isEmpty())) {
qCDebug(Log) << "Definition became invalid, trying re-lookup.";
m_definition = defData->repo->definitionForName(m_definition.name());
defData = DefinitionData::get(m_definition);
}
if (Q_UNLIKELY(!defData->repo && !defData->fileName.isEmpty()))
qCCritical(Log) << "Repository got deleted while a highlighter is still active!";
if (m_definition.isValid())
defData->load();
}
AbstractHighlighter::AbstractHighlighter() :
d_ptr(new AbstractHighlighterPrivate)
{
}
AbstractHighlighter::AbstractHighlighter(AbstractHighlighterPrivate *dd) :
d_ptr(dd)
{
}
AbstractHighlighter::~AbstractHighlighter()
{
delete d_ptr;
}
Definition AbstractHighlighter::definition() const
{
return d_ptr->m_definition;
}
void AbstractHighlighter::setDefinition(const Definition &def)
{
Q_D(AbstractHighlighter);
d->m_definition = def;
}
Theme AbstractHighlighter::theme() const
{
Q_D(const AbstractHighlighter);
return d->m_theme;
}
void AbstractHighlighter::setTheme(const Theme &theme)
{
Q_D(AbstractHighlighter);
d->m_theme = theme;
}
/**
* Returns the index of the first non-space character. If the line is empty,
* or only contains white spaces, text.size() is returned.
*/
static inline int firstNonSpaceChar(const QString & text)
{
for (int i = 0; i < text.length(); ++i) {
if (!text[i].isSpace()) {
return i;
}
}
return text.size();
}
State AbstractHighlighter::highlightLine(const QString& text, const State &state)
{
Q_D(AbstractHighlighter);
// verify definition, deal with no highlighting being enabled
d->ensureDefinitionLoaded();
const auto defData = DefinitionData::get(d->m_definition);
if (!d->m_definition.isValid() || !defData->isLoaded()) {
applyFormat(0, text.size(), Format());
return State();
}
// verify/initialize state
auto newState = state;
auto stateData = StateData::get(newState);
const DefinitionRef currentDefRef(d->m_definition);
if (!stateData->isEmpty() && (stateData->m_defRef != currentDefRef)) {
qCDebug(Log) << "Got invalid state, resetting.";
stateData->clear();
}
if (stateData->isEmpty()) {
stateData->push(defData->initialContext(), QStringList());
stateData->m_defRef = currentDefRef;
}
// process empty lines
if (text.isEmpty()) {
/**
* handle line empty context switches
* guard against endless loops
* see https://phabricator.kde.org/D18509
*/
int endlessLoopingCounter = 0;
while (!stateData->topContext()->lineEmptyContext().isStay()) {
if (!d->switchContext(stateData, stateData->topContext()->lineEmptyContext(), QStringList()))
break;
// guard against endless loops
++endlessLoopingCounter;
if (endlessLoopingCounter > 1024) {
qCDebug(Log) << "Endless switch context transitions for line empty context, aborting highlighting of line.";
break;
}
}
auto context = stateData->topContext();
applyFormat(0, 0, context->attributeFormat());
return newState;
}
int offset = 0, beginOffset = 0;
bool lineContinuation = false;
QHash skipOffsets;
/**
* current active format
* stored as pointer to avoid deconstruction/constructions inside the internal loop
* the pointers are stable, the formats are either in the contexts or rules
*/
auto currentFormat = &stateData->topContext()->attributeFormat();
/**
* cached first non-space character, needs to be computed if < 0
*/
int firstNonSpace = -1;
int lastOffset = offset;
int endlessLoopingCounter = 0;
do {
/**
* avoid that we loop endless for some broken hl definitions
*/
if (lastOffset == offset) {
++endlessLoopingCounter;
if (endlessLoopingCounter > 1024) {
qCDebug(Log) << "Endless state transitions, aborting highlighting of line.";
break;
}
} else {
// ensure we made progress, clear the endlessLoopingCounter
Q_ASSERT(offset > lastOffset);
lastOffset = offset;
endlessLoopingCounter = 0;
}
/**
* try to match all rules in the context in order of declaration in XML
*/
bool isLookAhead = false;
int newOffset = 0;
const Format *newFormat = nullptr;
for (const auto &rule : stateData->topContext()->rules()) {
/**
* filter out rules that require a specific column
*/
if ((rule->requiredColumn() >= 0) && (rule->requiredColumn() != offset)) {
continue;
}
/**
* filter out rules that only match for leading whitespace
*/
if (rule->firstNonSpace()) {
/**
* compute the first non-space lazy
* avoids computing it for contexts without any such rules
*/
if (firstNonSpace < 0) {
firstNonSpace = firstNonSpaceChar(text);
}
/**
* can we skip?
*/
if (offset > firstNonSpace) {
continue;
}
}
/**
* shall we skip application of this rule? two cases:
* - rule can't match at all => currentSkipOffset < 0
* - rule will only match for some higher offset => currentSkipOffset > offset
*/
const auto currentSkipOffset = skipOffsets.value(rule.get());
if (currentSkipOffset < 0 || currentSkipOffset > offset)
continue;
const auto newResult = rule->doMatch(text, offset, stateData->topCaptures());
newOffset = newResult.offset();
/**
* update skip offset if new one rules out any later match or is larger than current one
*/
if (newResult.skipOffset() < 0 || newResult.skipOffset() > currentSkipOffset)
skipOffsets.insert(rule.get(), newResult.skipOffset());
if (newOffset <= offset)
continue;
- // apply folding
- if (rule->endRegion().isValid())
+ /**
+ * apply folding.
+ * special cases:
+ * - rule with endRegion + beginRegion: in endRegion, the length is 0
+ * - rule with lookAhead: length is 0
+ */
+ if (rule->endRegion().isValid() && rule->beginRegion().isValid())
+ applyFolding(offset, 0, rule->endRegion());
+ else if (rule->endRegion().isValid())
applyFolding(offset, rule->isLookAhead() ? 0 : newOffset - offset, rule->endRegion());
if (rule->beginRegion().isValid())
applyFolding(offset, rule->isLookAhead() ? 0 : newOffset - offset, rule->beginRegion());
if (rule->isLookAhead()) {
Q_ASSERT(!rule->context().isStay());
d->switchContext(stateData, rule->context(), newResult.captures());
isLookAhead = true;
break;
}
d->switchContext(stateData, rule->context(), newResult.captures());
newFormat = rule->attributeFormat().isValid() ? &rule->attributeFormat() : &stateData->topContext()->attributeFormat();
if (newOffset == text.size() && std::dynamic_pointer_cast(rule))
lineContinuation = true;
break;
}
if (isLookAhead)
continue;
if (newOffset <= offset) { // no matching rule
if (stateData->topContext()->fallthrough()) {
d->switchContext(stateData, stateData->topContext()->fallthroughContext(), QStringList());
continue;
}
newOffset = offset + 1;
newFormat = &stateData->topContext()->attributeFormat();
}
/**
* if we arrive here, some new format has to be set!
*/
Q_ASSERT(newFormat);
/**
* on format change, apply the last one and switch to new one
*/
if (newFormat != currentFormat && newFormat->id() != currentFormat->id()) {
if (offset > 0)
applyFormat(beginOffset, offset - beginOffset, *currentFormat);
beginOffset = offset;
currentFormat = newFormat;
}
/**
* we must have made progress if we arrive here!
*/
Q_ASSERT(newOffset > offset);
offset = newOffset;
} while (offset < text.size());
/**
* apply format for remaining text, if any
*/
if (beginOffset < offset)
applyFormat(beginOffset, text.size() - beginOffset, *currentFormat);
/**
* handle line end context switches
* guard against endless loops
* see https://phabricator.kde.org/D18509
*/
{
int endlessLoopingCounter = 0;
while (!stateData->topContext()->lineEndContext().isStay() && !lineContinuation) {
if (!d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList()))
break;
// guard against endless loops
++endlessLoopingCounter;
if (endlessLoopingCounter > 1024) {
qCDebug(Log) << "Endless switch context transitions for line end context, aborting highlighting of line.";
break;
}
}
}
return newState;
}
bool AbstractHighlighterPrivate::switchContext(StateData *data, const ContextSwitch &contextSwitch, const QStringList &captures)
{
// kill as many items as requested from the stack, will always keep the initial context alive!
const bool initialContextSurvived = data->pop(contextSwitch.popCount());
// if we have a new context to add, push it
// then we always "succeed"
if (contextSwitch.context()) {
data->push(contextSwitch.context(), captures);
return true;
}
// else we abort, if we did try to pop the initial context
return initialContextSurvived;
}
void AbstractHighlighter::applyFolding(int offset, int length, FoldingRegion region)
{
Q_UNUSED(offset);
Q_UNUSED(length);
Q_UNUSED(region);
}