11enum class ScanKind { Code, LineComment, BlockComment,
String };
14 ScanKind
kind = ScanKind::Code;
19void advance(ScanState& state, std::string_view
source,
size_t& i,
size_t end) {
23 if (
state.kind == ScanKind::LineComment) {
24 if (
value ==
'\n')
state.kind = ScanKind::Code;
28 if (
state.kind == ScanKind::BlockComment) {
29 if (
value ==
'*' && next ==
'/') {
30 state.kind = ScanKind::Code;
37 if (
state.kind == ScanKind::String) {
47 state.kind = ScanKind::Code;
54 if (
value ==
'/' && next ==
'/') {
55 state.kind = ScanKind::LineComment;
59 if (
value ==
'/' && next ==
'*') {
60 state.kind = ScanKind::BlockComment;
66 state.kind = ScanKind::String;
75std::string indentText(
unsigned depth,
const FormatOptions&
options) {
76 if (
depth == 0)
return {};
77 if (
options.insertSpaces)
return std::string(
static_cast<size_t>(
depth) *
options.tabSize,
' ');
78 return std::string(
depth,
'\t');
81std::string rtrim(std::string_view
line) {
84 return std::string(
line.substr(0,
end));
87unsigned leadingCloses(std::string_view
line, ScanState state) {
90 while (i <
line.size() && (
line[i] ==
' ' ||
line[i] ==
'\t')) ++i;
91 while (i <
line.size()) {
92 const size_t before = i;
94 advance(state,
line, i,
line.size());
95 if (
kind != ScanKind::Code)
continue;
96 if (before >=
line.size())
break;
101 else if (!std::isspace(
static_cast<unsigned char>(
value)))
103 if (i == before) ++i;
108int braceDelta(std::string_view
line, ScanState& state) {
111 while (i <
line.size()) {
112 const size_t before = i;
114 advance(state,
line, i,
line.size());
115 if (
kind != ScanKind::Code)
continue;
116 if (before >=
line.size())
break;
121 if (i == before) ++i;
128 for (
size_t i = 0; i <
offset && i <
source.size(); ++i) {
145 if (newline == std::string_view::npos)
return source.size();
152 return {{0, 0}, positionAtOffset(
source,
source.size())};
164 if (startLine > last) startLine = last;
165 if (endLineInclusive > last) endLineInclusive = last;
166 if (endLineInclusive < startLine) endLineInclusive = startLine;
169 if (endLineInclusive < last)
170 range.
end = {endLineInclusive + 1, 0};
176std::string
sliceLines(std::string_view
source,
size_t startLine,
size_t endLineInclusive) {
185 if (
range ==
nullptr) {
198 result.reserve(
source.size());
201 size_t lineBegin = 0;
205 for (
size_t i = 0; i <=
source.size(); ++i) {
207 const std::string_view raw =
source.substr(lineBegin, i - lineBegin);
208 const std::string trimmed = rtrim(raw);
210 while (content < trimmed.size() && (trimmed[content] ==
' ' || trimmed[content] ==
'\t')) ++content;
211 const bool blank = content == trimmed.size();
213 if (
state.kind == ScanKind::BlockComment) result += trimmed;
214 }
else if (
state.kind == ScanKind::BlockComment) {
217 const unsigned closes = leadingCloses(trimmed,
state);
218 const int display = indent -
static_cast<int>(closes);
219 result += indentText(display < 0 ? 0 :
static_cast<unsigned>(display), normalized);
220 result += trimmed.substr(content);
222 indent += braceDelta(trimmed,
state);
223 if (indent < 0) indent = 0;
224 if (i <
source.size()) result +=
'\n';
234 ScanKind scan = ScanKind::Code;
236 std::vector<Open> stack;
237 std::vector<FoldingRange> result;
240 for (
size_t i = 0; i <
source.size();) {
241 const size_t before = i;
249 if (
kind == ScanKind::Code &&
state.kind == ScanKind::BlockComment) {
250 stack.push_back({
line,
'*', ScanKind::BlockComment});
253 if (
kind == ScanKind::BlockComment &&
state.kind == ScanKind::Code) {
254 if (!stack.empty() && stack.back().kind ==
'*') {
255 const size_t start = stack.back().line;
261 if (
kind != ScanKind::Code)
continue;
263 else if ((
value ==
'}' ||
value ==
']') && !stack.empty() && stack.back().kind !=
'*') {
264 const size_t start = stack.back().line;
268 if (i == before) ++i;
std::array< float, 3 > position
const SquirrelValueOptions & options
const UnitySourceAsset & source
size_t offsetAt(std::string_view source, Position position) noexcept
Converts an LSP position into a UTF-8 byte offset (same contract as the rest of the server).
size_t lastLineIndex(std::string_view source) noexcept
Last 0-based line index (empty source is line 0).
std::string sliceLines(std::string_view source, size_t startLine, size_t endLineInclusive)
Source bytes for coveringLines of the same line span.
bool applyIncremental(std::string &source, const Range *range, std::string_view text)
Applies one LSP content change.
std::string formatEveScript(std::string_view source, const FormatOptions &options)
Indents EveScript by braces/brackets and trims trailing whitespace.
Range coveringLines(std::string_view source, size_t startLine, size_t endLineInclusive) noexcept
Half-open LSP range covering startLine through endLine inclusive. Ends at the start of the following ...
Range documentRange(std::string_view source) noexcept
Full-document range covering every character in source.
std::vector< FoldingRange > foldingRanges(std::string_view source)
Brace, bracket, and block-comment folds that span more than one line.
constexpr HexDirection next(HexDirection d) noexcept
The next direction clockwise (NW wraps to NE).
enum EVENGINE_API_FOUNDATION String
OT_STRING.