Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SQL Server typos and keyword completion modifier #2460

Merged
merged 14 commits into from
Apr 23, 2015
19 changes: 12 additions & 7 deletions demo/kitchen-sink/docs/sqlserver.sqlserver
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
-- =============================================
-- Author: Morgan Yarbrough
-- Create date: 4/27/2015
-- Description: Test Procedure that shows off language features.
-- Includes non-standard folding using region comments using either
-- line comments or block comments (both are demonstrated below)
-- Description: Test procedure that shows off language features.
-- Includes non-standard folding with region comments using either
-- line comments or block comments (both are demonstrated below).
-- This mode imitates SSMS and it designed to be used with SQL Server theme.
-- =============================================
CREATE PROCEDURE dbo.TestProcedure

--#region parameters
@vint INT = 1
,@vdate DATE = NULL
,@vdatetime DATETIME = DATEADD (dd, 1, GETDATE())
,@vdatetime DATETIME = DATEADD(dd, 1, GETDATE())
,@vvarchar VARCHAR(MAX) = ''
--#endregion

Expand All @@ -38,16 +38,16 @@ BEGIN
-- another folding demonstration
IF @vint = 1
BEGIN
SET @vvarchar='one'
SET @vint = DATEDIFFT(dd, @vdate, @vdatetime)
SET @vvarchar = 'one'
SET @vint = DATEDIFF(dd, @vdate, @vdatetime)
END

-- this mode handles strings properly
DECLARE @sql NVARCHAR(4000) = N'SELECT TOP(1) OrderID
FROM Orders
WHERE @OrderDate > GETDATE()'

-- this mode is aware of build in stored procedures
-- this mode is aware of built in stored procedures
EXECUTE sp_executesql @sql

-- demonstrating some syntax highlighting
Expand All @@ -60,4 +60,9 @@ BEGIN
WHERE CompanyName NOT LIKE '%something'
OR CompanyName IS NULL
OR CompanyName IN ('bla', 'nothing')

-- this mode includes snippets
-- place your cusor at the end of the line below and trigger auto complete (Ctrl+Space)
createpr

END
27 changes: 27 additions & 0 deletions lib/ace/mode/sqlserver.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,33 @@ oop.inherits(Mode, TextMode);
(function() {
this.lineCommentStart = "--";
this.blockComment = {start: "/*", end: "*/"};

/**
* Override keyword completions to ensure proper case for completions
* and use smart meta tags instead of 'keyword' for all completions.
*/
this.getCompletions = function(state, session, pos, prefix) {
var keywords = this.$keywordList || this.$createKeywordList();
var types = session.$mode.$highlightRules.keywordTypes;

return keywords.map(function(word) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we just use types skipping keywordList entirely?
keywordList removes some information that highlighter doesn't need and here we are restoring that using slow indexOf in a large array

var meta = 'keyword';
if (types.builtInStoredProcedures.indexOf(word) !== -1) meta = "procedure";
else {
word = word.toUpperCase(); //all others are upper case
if (types.builtinFunctions.indexOf(word) !== -1) meta = "function";
else if (types.dataTypes.indexOf(word) !== -1) meta = "type";
else if (types.setStatements.indexOf(word) !== -1) meta = "statement";
else if (types.logicalOperators.indexOf(word) !== -1) meta = "operator";
}
return {
name: word,
value: word,
score: 0,
meta: meta
};
});
};

this.$id = "ace/mode/sql";
}).call(Mode.prototype);
Expand Down
34 changes: 19 additions & 15 deletions lib/ace/mode/sqlserver_highlight_rules.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@ var SqlServerHighlightRules = function() {
/* https://msdn.microsoft.com/en-us/library/ms177520.aspx */
"@@CONNECTIONS|@@CPU_BUSY|@@IDLE|@@IO_BUSY|@@PACKET_ERRORS|@@PACK_RECEIVED|@@PACK_SENT|@@TIMETICKS|@@TOTAL_ERRORS|@@TOTAL_READ|@@TOTAL_WRITE|FN_VIRTUALFILESTATS|" +
/* https://msdn.microsoft.com/en-us/library/ms188353.aspx */
"PATINDEX|TEXTPTR|TEXTVALID"
"PATINDEX|TEXTPTR|TEXTVALID|" +
/* other */
"COALESCE|NULLIF"
);


Expand All @@ -104,30 +106,22 @@ var SqlServerHighlightRules = function() {
keywords += "|TYPE";


//remove any other built in things from key word list
//remove specific built in types from keyword list
keywords = keywords.split('|');
keywords = keywords.filter(function(value, index, self) {
return logicalOperators.split('|').indexOf(value) === -1 && builtinFunctions.split('|').indexOf(value) === -1 && dataTypes.split('|').indexOf(value) === -1;
});
keywords = keywords.sort().join('|');


var keywordMapper = this.createKeywordMapper({
"constant.language": logicalOperators,
"storage.type": dataTypes,
"support.function": builtinFunctions,
"support.storedprocedure": builtInStoredProcedures,
"keyword": keywords,
}, "identifier", true);


// createKeywordMapper ignores case which we want because SqlServer keywords are not case sensitive which causes our keywords to get changed to lowercase.
// However, the preferred standard for keywords is uppercase, so this transforms them back to uppercase for code completion
// EXCEPTION: build in stored procedures are lower case
for (var i = 0; i < this.$keywordList.length; i++) {
var keyword = this.$keywordList[i];
if (builtInStoredProcedures.indexOf(keyword) !== -1) continue;
this.$keywordList[i] = keyword.toUpperCase();
}



//https://msdn.microsoft.com/en-us/library/ms190356.aspx
var setStatements = "SET ANSI_DEFAULTS|SET ANSI_NULLS|SET ANSI_NULL_DFLT_OFF|SET ANSI_NULL_DFLT_ON|SET ANSI_PADDING|SET ANSI_WARNINGS|SET ARITHABORT|SET ARITHIGNORE|SET CONCAT_NULL_YIELDS_NULL|SET CURSOR_CLOSE_ON_COMMIT|SET DATEFIRST|SET DATEFORMAT|SET DEADLOCK_PRIORITY|SET FIPS_FLAGGER|SET FMTONLY|SET FORCEPLAN|SET IDENTITY_INSERT|SET IMPLICIT_TRANSACTIONS|SET LANGUAGE|SET LOCK_TIMEOUT|SET NOCOUNT|SET NOEXEC|SET NUMERIC_ROUNDABORT|SET OFFSETS|SET PARSEONLY|SET QUERY_GOVERNOR_COST_LIMIT|SET QUOTED_IDENTIFIER|SET REMOTE_PROC_TRANSACTIONS|SET ROWCOUNT|SET SHOWPLAN_ALL|SET SHOWPLAN_TEXT|SET SHOWPLAN_XML|SET STATISTICS IO|SET STATISTICS PROFILE|SET STATISTICS TIME|SET STATISTICS XML|SET TEXTSIZE|SET XACT_ABORT".split('|');
Expand All @@ -147,7 +141,7 @@ var SqlServerHighlightRules = function() {
regex: "'",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like the // ' string rule a little bellow is unnecessary.

next: [{
token: "constant.language.escape",
regex: /\\'/
regex: /''/
}, {
token: "string.end",
next: "start",
Expand All @@ -171,7 +165,7 @@ var SqlServerHighlightRules = function() {
regex: "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
}, {
token: keywordMapper,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this was the unnecessary rule you were referring to, correct? I think I copied that rule from somewhere else

regex: "@{0,2}[a-zA-Z_$][a-zA-Z0-9_$]*\\b" //up to 2 @symbols for some build in functions
regex: "@{0,2}[a-zA-Z_$][a-zA-Z0-9_$]*\\b" //up to 2 @symbols for some built in functions
}, {
token: "constant.class",
regex: "@@?[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
Expand Down Expand Up @@ -216,6 +210,16 @@ var SqlServerHighlightRules = function() {
this.embedRules(DocCommentHighlightRules, "doc-", [DocCommentHighlightRules.getEndRule("start")]);

this.normalizeRules();

// export types for overriding get completions
this.keywordTypes = {
builtInStoredProcedures: builtInStoredProcedures.split('|'),
logicalOperators: logicalOperators.split('|'),
builtinFunctions: builtinFunctions.split('|'),
dataTypes: dataTypes.split('|'),
setStatements: setStatements,
};

};

oop.inherits(SqlServerHighlightRules, TextHighlightRules);
Expand Down
16 changes: 15 additions & 1 deletion lib/ace/snippets/sqlserver.snippets
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ snippet dateadd
# DATEFROMPARTS
snippet datefromparts
DATEFROMPARTS(${1:year}, ${2:month}, ${3:day})
# OBJECT_DEFINITION
snippet objectdef
SELECT OBJECT_DEFINITION(OBJECT_ID('${1:sys.server_permissions /*object name*/}'))
# STUFF XML
snippet stuffxml
STUFF((SELECT ', ' + ${1:ColumnName}
FROM ${2:TableName}
WHERE ${3:WhereClause}
FOR XML PATH('')), 1, 1, '') AS ${4:Alias}
${5:/*https://msdn.microsoft.com/en-us/library/ms188043.aspx*/}
# Create Procedure
snippet createproc
-- =============================================
Expand All @@ -30,12 +40,14 @@ snippet createproc
-- Description: ${3:Description}
-- =============================================
CREATE PROCEDURE ${4:Procedure_Name}
-- Add the parameters for the stored procedure here
${5:/*Add the parameters for the stored procedure here*/}
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from interfering with SELECT statements.
SET NOCOUNT ON;

${6:/*Add the T-SQL statements to compute the return value here*/}

END
GO
# Create Scalar Function
Expand All @@ -52,5 +64,7 @@ snippet createfn
BEGIN
DECLARE @Result ${5:Function_Data_Type}

${6:/*Add the T-SQL statements to compute the return value here*/}

END
GO