55 */
66
77const vscode = require ( "vscode" ) ;
8- const { VarsKeywords, ScopedVarPrefixes, Controls } = require ( "./constants" ) ;
8+ const { VarsKeywords, ScopedVarPrefixes, ControlKeywords } = require ( "./constants" ) ;
99
1010/**
1111 * Formatter class for Sphere script (.scp) files.
1212 * Provides document formatting functionality for VS Code.
1313 */
1414class SCPFormatter {
15+ /**
16+ * Returns true when a line is a comment and should not be formatted.
17+ *
18+ * @param {string } line - The line to check
19+ * @returns {boolean } True if the line is a comment
20+ */
21+ isCommentLine ( line ) {
22+ return line . trim ( ) . startsWith ( "//" ) ;
23+ }
1524 /**
1625 * Main method called by VS Code to format a document.
1726 * Processes each line of the document and applies formatting rules.
@@ -44,15 +53,9 @@ class SCPFormatter {
4453 * @param {string } line - The line to format
4554 * @returns {string } The formatted line with uppercase triggers
4655 */
47- formatTriggers ( line ) {
48- const pattern = / ( \b o n = @ \w + \b [ ^ \s / ] * ) (? ! \S ) / gi;
49-
50- // Do not format commented lines
51- if ( line . trim ( ) . startsWith ( "//" ) ) {
52- return line ;
53- }
54-
55- return line . replace ( pattern , ( match ) => {
56+ formatTriggers ( sourceLine ) {
57+ const triggerPattern = / ( \b o n = @ \w + \b [ ^ \s / ] * ) (? ! \S ) / gi;
58+ return sourceLine . replace ( triggerPattern , ( match ) => {
5659 return match . toUpperCase ( ) ;
5760 } ) ;
5861 }
@@ -64,13 +67,13 @@ class SCPFormatter {
6467 * @param {string } line - The line to format
6568 * @returns {string } The formatted line with uppercase variable keywords
6669 */
67- formatVars ( line ) {
70+ formatAssignmentKeywords ( sourceLine ) {
6871 for ( const varKeyword of VarsKeywords ) {
69- const pattern = new RegExp ( `^[ \\t]*${ varKeyword } =` , "i" ) ;
70- line = line . replace ( pattern , `${ varKeyword . toUpperCase ( ) } =` ) ;
72+ const assignmentPattern = new RegExp ( `^[ \\t]*${ varKeyword } =` , "i" ) ;
73+ sourceLine = sourceLine . replace ( assignmentPattern , `${ varKeyword . toUpperCase ( ) } =` ) ;
7174 }
7275
73- return line ;
76+ return sourceLine ;
7477 }
7578
7679 /**
@@ -80,21 +83,15 @@ class SCPFormatter {
8083 * @param {string } line - The line to format
8184 * @returns {string } The formatted line with uppercase scoped prefixes
8285 */
83- formatScopedVars ( line ) {
84- const trimmed = line . trim ( ) ;
85-
86- if ( trimmed . startsWith ( "//" ) ) {
87- return line ;
88- }
89-
86+ formatScopedAssignments ( sourceLine ) {
9087 for ( const prefix of ScopedVarPrefixes ) {
91- const pattern = new RegExp ( `^(\\s*)(${ prefix } )(?=\\.|=)` , "i" ) ;
92- line = line . replace ( pattern , ( match , whitespace , keyword ) => {
88+ const scopedPattern = new RegExp ( `^(\\s*)(${ prefix } )(?=\\.|=)` , "i" ) ;
89+ sourceLine = sourceLine . replace ( scopedPattern , ( match , whitespace , keyword ) => {
9390 return whitespace + keyword . toUpperCase ( ) ;
9491 } ) ;
9592 }
9693
97- return line ;
94+ return sourceLine ;
9895 }
9996
10097 /**
@@ -104,23 +101,16 @@ class SCPFormatter {
104101 * @param {string } line - The line to format
105102 * @returns {string } The formatted line with uppercase control keywords
106103 */
107- formatControls ( line ) {
108- const trimmed = line . trim ( ) ;
109-
110- // Skip comment lines
111- if ( trimmed . startsWith ( "//" ) ) {
112- return line ;
113- }
114-
115- for ( const control of Controls ) {
104+ formatControlKeywords ( sourceLine ) {
105+ for ( const control of ControlKeywords ) {
116106 // Match control keywords at the beginning of line (possibly with whitespace)
117- const pattern = new RegExp ( `^(\\s*)(${ control } )\\b` , "i" ) ;
118- line = line . replace ( pattern , ( match , whitespace , keyword ) => {
107+ const controlPattern = new RegExp ( `^(\\s*)(${ control } )\\b` , "i" ) ;
108+ sourceLine = sourceLine . replace ( controlPattern , ( match , whitespace , keyword ) => {
119109 return whitespace + keyword . toUpperCase ( ) ;
120110 } ) ;
121111 }
122112
123- return line ;
113+ return sourceLine ;
124114 }
125115
126116 /**
@@ -130,22 +120,15 @@ class SCPFormatter {
130120 * @param {string } line - The line to format
131121 * @returns {string } The formatted line with uppercase section headers
132122 */
133- formatSections ( line ) {
134- const trimmed = line . trim ( ) ;
135-
136- // Skip comment lines
137- if ( trimmed . startsWith ( "//" ) ) {
138- return line ;
139- }
140-
123+ formatSectionHeaders ( sourceLine ) {
141124 // Format section headers like [TYPEDEF], [ITEMDEF], [CHARDEF], etc.
142125 const sectionPattern = / ^ \s * \[ ( \w + ) ( \s + .* ) ? \] \s * $ / i;
143- line = line . replace ( sectionPattern , ( match , sectionType , rest ) => {
126+ sourceLine = sourceLine . replace ( sectionPattern , ( match , sectionType , rest ) => {
144127 rest = rest || "" ;
145128 return `[${ sectionType . toUpperCase ( ) } ${ rest } ]` ;
146129 } ) ;
147130
148- return line ;
131+ return sourceLine ;
149132 }
150133
151134 /**
@@ -155,27 +138,20 @@ class SCPFormatter {
155138 * @param {string } line - The line to format
156139 * @returns {string } The formatted line with uppercase function calls
157140 */
158- formatFunctions ( line ) {
159- const trimmed = line . trim ( ) ;
160-
161- // Skip comment lines
162- if ( trimmed . startsWith ( "//" ) ) {
163- return line ;
164- }
165-
141+ formatCommandCalls ( sourceLine ) {
166142 // Common Sphere functions that should be uppercase
167- const functions = [
143+ const commandKeywords = [
168144 "SAY" , "EMOTE" , "SYSMESSAGE" , "DIALOG" , "NEWITEM" , "EQUIP" , "UNEQUIP" ,
169145 "GO" , "FACE" , "FOLLOW" , "SPEAK" , "BOUNCE" , "CONSUME" , "REMOVE"
170146 ] ;
171147
172- for ( const func of functions ) {
148+ for ( const func of commandKeywords ) {
173149 // Match function calls (word followed by space or opening parenthesis)
174- const pattern = new RegExp ( `\\b(${ func } )\\b(?=\\s|\\(|$)` , "gi" ) ;
175- line = line . replace ( pattern , func . toUpperCase ( ) ) ;
150+ const commandPattern = new RegExp ( `\\b(${ func } )\\b(?=\\s|\\(|$)` , "gi" ) ;
151+ sourceLine = sourceLine . replace ( commandPattern , func . toUpperCase ( ) ) ;
176152 }
177153
178- return line ;
154+ return sourceLine ;
179155 }
180156
181157 /**
@@ -185,24 +161,25 @@ class SCPFormatter {
185161 * @param {string } line - The line to format
186162 * @returns {string } The fully formatted line
187163 */
188- formatLine ( line ) {
189- // Do not format commented lines
190- if ( ! line . trim ( ) . startsWith ( "//" ) ) {
191- // Apply formatting in order:
192- // 1. Section headers (must be first to avoid conflicts)
193- // 2. Triggers (ON= patterns)
194- // 3. Variables (keyword= patterns)
195- // 4. Control structures (BEGIN, IF, etc.)
196- // 5. Function calls (SAY, EMOTE, etc.)
197- line = this . formatSections ( line ) ;
198- line = this . formatTriggers ( line ) ;
199- line = this . formatScopedVars ( line ) ;
200- line = this . formatVars ( line ) ;
201- line = this . formatControls ( line ) ;
202- line = this . formatFunctions ( line ) ;
164+ formatLine ( sourceLine ) {
165+ if ( this . isCommentLine ( sourceLine ) ) {
166+ return sourceLine ;
203167 }
204168
205- return line ;
169+ // Apply formatting in order:
170+ // 1. Section headers (must be first to avoid conflicts)
171+ // 2. Triggers (ON= patterns)
172+ // 3. Variables (keyword= patterns)
173+ // 4. Control structures (BEGIN, IF, etc.)
174+ // 5. Function calls (SAY, EMOTE, etc.)
175+ sourceLine = this . formatSectionHeaders ( sourceLine ) ;
176+ sourceLine = this . formatTriggers ( sourceLine ) ;
177+ sourceLine = this . formatScopedAssignments ( sourceLine ) ;
178+ sourceLine = this . formatAssignmentKeywords ( sourceLine ) ;
179+ sourceLine = this . formatControlKeywords ( sourceLine ) ;
180+ sourceLine = this . formatCommandCalls ( sourceLine ) ;
181+
182+ return sourceLine ;
206183 }
207184}
208185
0 commit comments