+2017-08-04 Devin Rousso <drousso@apple.com>
+
+ Web Inspector: add source view for WebGL shader programs
+ https://bugs.webkit.org/show_bug.cgi?id=138593
+ <rdar://problem/18936194>
+
+ Reviewed by Matt Baker.
+
+ * inspector/canvas/requestShaderSource-expected.txt: Added.
+ * inspector/canvas/requestShaderSource.html: Added.
+
+ * inspector/canvas/resources/shaderProgram-utilities.js:
+ (linkProgram):
+ (linkProgram.typeForScript):
+ (linkProgram.createShaderFromScript):
+
+ * platform/win/TestExpectations:
+
2017-08-04 Said Abou-Hallawa <sabouhallawa@apple.com>
RenderImageResourceStyleImage::image() should return the nullImage() if the image is not available
--- /dev/null
+Test compilation of shaders after being attached to a program, with and without syntax errors.
+
+
+== Running test suite: Canvas.getShaderSource
+-- Running test case: Canvas.requestShaderSource.vertexShader
+
+ void main(void) {
+ gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
+ }
+
+
+-- Running test case: Canvas.requestShaderSource.fragmentShader
+
+ precision mediump float;
+
+ void main(void) {
+ gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
+ }
+
+
+-- Running test case: Canvas.requestShaderSource.invalidProgramId
+PASS: Should produce an error.
+Error: No shader program for given identifier.
+
+-- Running test case: Canvas.requestShaderSource.invalidShaderType
+PASS: Should produce an error.
+Error: No shader for given type.
+
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
+<script src="resources/shaderProgram-utilities.js"></script>
+<script id="vertex-shader" type="x-shader/x-vertex">
+ void main(void) {
+ gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
+ }
+</script>
+<script id="fragment-shader" type="x-shader/x-fragment">
+ precision mediump float;
+
+ void main(void) {
+ gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
+ }
+</script>
+<script>
+function load() {
+ createProgram("webgl");
+ linkProgram("vertex-shader", "fragment-shader");
+
+ runTest();
+}
+
+function test() {
+ let suite = InspectorTest.createAsyncSuite("Canvas.getShaderSource");
+
+ suite.addTestCase({
+ name: "Canvas.requestShaderSource.vertexShader",
+ description: "Tests requesting the source code of a program's vertex shader.",
+ test(resolve, reject) {
+ let shaderProgram = WI.canvasManager.shaderPrograms[0];
+ if (!shaderProgram) {
+ reject("Missing shader program")
+ return;
+ }
+
+ CanvasAgent.requestShaderSource(shaderProgram.identifier, CanvasAgent.ShaderType.Vertex)
+ .then(({content}) => InspectorTest.log(content))
+ .then(resolve, reject);
+ }
+ });
+
+ suite.addTestCase({
+ name: "Canvas.requestShaderSource.fragmentShader",
+ description: "Tests requesting the source code of a program's fragment shader.",
+ test(resolve, reject) {
+ let shaderProgram = WI.canvasManager.shaderPrograms[0];
+ if (!shaderProgram) {
+ reject("Missing shader program")
+ return;
+ }
+
+ CanvasAgent.requestShaderSource(shaderProgram.identifier, CanvasAgent.ShaderType.Fragment)
+ .then(({content}) => InspectorTest.log(content))
+ .then(resolve, reject);
+ }
+ });
+
+ suite.addTestCase({
+ name: "Canvas.requestShaderSource.invalidProgramId",
+ description: "Invalid program identifiers should cause an error.",
+ test(resolve, reject) {
+ const programId = "INVALID_PROGRAM_ID";
+ const shaderType = "INVALID_SHADER_TYPE";
+ CanvasAgent.requestShaderSource(programId, shaderType, (error) => {
+ InspectorTest.expectThat(error, "Should produce an error.");
+ InspectorTest.log("Error: " + error);
+ resolve();
+ });
+ }
+ });
+
+ suite.addTestCase({
+ name: "Canvas.requestShaderSource.invalidShaderType",
+ description: "Invalid shader types should cause an error.",
+ test(resolve, reject) {
+ let shaderProgram = WI.canvasManager.shaderPrograms[0];
+ if (!shaderProgram) {
+ reject("Missing shader program")
+ return;
+ }
+
+ const shaderType = "INVALID_SHADER_TYPE";
+ CanvasAgent.requestShaderSource(shaderProgram.identifier, shaderType, (error) => {
+ InspectorTest.expectThat(error, "Should produce an error.");
+ InspectorTest.log("Error: " + error);
+ resolve();
+ });
+ }
+ });
+
+ suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body onload="load()">
+ <p>Test compilation of shaders after being attached to a program, with and without syntax errors.</p>
+</body>
+</html>
program = context.createProgram();
}
+function linkProgram(vertexShaderIdentifier, fragmentShaderIdentifier) {
+ function typeForScript(script) {
+ if (script.type === "x-shader/x-vertex")
+ return context.VERTEX_SHADER;
+ if (script.type === "x-shader/x-fragment")
+ return context.FRAGMENT_SHADER;
+
+ console.assert(false, "Unexpected script x-shader type: " + script.type);
+ }
+
+ function createShaderFromScript(scriptIdentifier) {
+ let script = document.getElementById(scriptIdentifier);
+ let shader = context.createShader(typeForScript(script));
+ context.attachShader(program, shader);
+ context.shaderSource(shader, script.text);
+ context.compileShader(shader);
+ }
+
+ createShaderFromScript(vertexShaderIdentifier);
+ createShaderFromScript(fragmentShaderIdentifier);
+ context.linkProgram(program);
+}
+
function deleteProgram() {
context.deleteProgram(program);
program = null;
inspector/canvas/create-context-webgl2.html [ Skip ]
inspector/canvas/requestContent-webgl.html [ Skip ]
inspector/canvas/requestContent-webgl2.html [ Skip ]
+inspector/canvas/requestShaderSource.html [ Skip ]
inspector/canvas/resolveCanvasContext-webgl.html [ Skip ]
inspector/canvas/resolveCanvasContext-webgl2.html [ Skip ]
inspector/canvas/shaderProgram-add-remove-webgl.html [ Skip ]
+2017-08-04 Devin Rousso <drousso@apple.com>
+
+ Web Inspector: add source view for WebGL shader programs
+ https://bugs.webkit.org/show_bug.cgi?id=138593
+ <rdar://problem/18936194>
+
+ Reviewed by Matt Baker.
+
+ * inspector/protocol/Canvas.json:
+ - Add `ShaderType` enum that contains "vertex" and "fragment".
+ - Add `requestShaderSource` command that will return the original source code for a given
+ shader program and shader type.
+
2017-08-03 Filip Pizlo <fpizlo@apple.com>
The allocator used to allocate memory for MarkedBlocks and LargeAllocations should not be the Subspace itself
"enum": ["canvas-2d", "webgl", "webgl2", "webgpu"],
"description": "The type of rendering context backing the canvas element."
},
+ {
+ "id": "ShaderType",
+ "type": "string",
+ "enum": ["fragment", "vertex"],
+ "description": "Shader type. WebGL supports vertex and fragment shaders."
+ },
{
"id": "ContextAttributes",
"type": "object",
"parameters": [
{ "name": "canvasId", "$ref": "CanvasId" }
]
+ },
+ {
+ "name": "requestShaderSource",
+ "description": "",
+ "parameters": [
+ { "name": "programId", "$ref": "ProgramId" },
+ { "name": "shaderType", "$ref": "ShaderType" }
+ ],
+ "returns": [
+ { "name": "content", "type": "string" }
+ ]
}
],
"events": [
+2017-08-04 Devin Rousso <drousso@apple.com>
+
+ Web Inspector: add source view for WebGL shader programs
+ https://bugs.webkit.org/show_bug.cgi?id=138593
+ <rdar://problem/18936194>
+
+ Reviewed by Matt Baker.
+
+ Test: inspector/canvas/requestShaderSource.html
+
+ * inspector/InspectorCanvasAgent.h:
+ * inspector/InspectorCanvasAgent.cpp:
+ (WebCore::InspectorCanvasAgent::requestShaderSource):
+
+ * inspector/InspectorShaderProgram.h:
+ * inspector/InspectorShaderProgram.cpp:
+ (WebCore::InspectorShaderProgram::shaderForType):
+
2017-08-04 Matt Lewis <jlewis3@apple.com>
Unreviewed, rolling out r220288.
#if ENABLE(WEBGL)
#include "JSWebGLRenderingContext.h"
#include "WebGLProgram.h"
+#include "WebGLShader.h"
#endif
#if ENABLE(WEBGL2)
didFinishRecordingCanvasFrame(inspectorCanvas->canvas(), true);
}
+void InspectorCanvasAgent::requestShaderSource(ErrorString& errorString, const String& programId, const String& shaderType, String* content)
+{
+#if ENABLE(WEBGL)
+ auto* inspectorProgram = assertInspectorProgram(errorString, programId);
+ if (!inspectorProgram)
+ return;
+
+ auto* shader = inspectorProgram->shaderForType(shaderType);
+ if (!shader) {
+ errorString = ASCIILiteral("No shader for given type.");
+ return;
+ }
+
+ *content = shader->getSource();
+#else
+ UNUSED_PARAM(programId);
+ UNUSED_PARAM(shaderType);
+ UNUSED_PARAM(content);
+ errorString = ASCIILiteral("WebGL is not supported.");
+#endif
+}
+
void InspectorCanvasAgent::frameNavigated(Frame& frame)
{
if (frame.isMainFrame()) {
void resolveCanvasContext(ErrorString&, const String& canvasId, const String* const objectGroup, RefPtr<Inspector::Protocol::Runtime::RemoteObject>&) override;
void requestRecording(ErrorString&, const String& canvasId, const bool* const singleFrame, const int* const memoryLimit) override;
void cancelRecording(ErrorString&, const String& canvasId) override;
+ void requestShaderSource(ErrorString&, const String& programId, const String& shaderType, String*) override;
// InspectorInstrumentation
void frameNavigated(Frame&);
#include "config.h"
#include "InspectorShaderProgram.h"
+#include "GraphicsContext3D.h"
+#include "GraphicsTypes3D.h"
#include "HTMLCanvasElement.h"
#include "InspectorCanvas.h"
#include "WebGLProgram.h"
#include "WebGLRenderingContextBase.h"
+#include "WebGLShader.h"
#include <inspector/IdentifiersFactory.h>
using namespace Inspector;
return downcast<WebGLRenderingContextBase>(context);
}
+WebGLShader* InspectorShaderProgram::shaderForType(const String& protocolType)
+{
+ GC3Denum shaderType;
+ if (protocolType == "vertex")
+ shaderType = GraphicsContext3D::VERTEX_SHADER;
+ else if (protocolType == "fragment")
+ shaderType = GraphicsContext3D::FRAGMENT_SHADER;
+ else
+ return nullptr;
+
+ return m_program.getAttachedShader(shaderType);
+}
+
} // namespace WebCore
class InspectorCanvas;
class WebGLProgram;
class WebGLRenderingContextBase;
+class WebGLShader;
typedef String ErrorString;
InspectorCanvas& canvas() const { return m_canvas; }
WebGLRenderingContextBase* context() const;
WebGLProgram& program() const { return m_program; }
+ WebGLShader* shaderForType(const String&);
~InspectorShaderProgram() { }
+2017-08-04 Devin Rousso <drousso@apple.com>
+
+ Web Inspector: add source view for WebGL shader programs
+ https://bugs.webkit.org/show_bug.cgi?id=138593
+ <rdar://problem/18936194>
+
+ Reviewed by Matt Baker.
+
+ Shader programs are now listed in the Resources sidebar as items within the owner Canvas
+ context. When selected, the shown content view has two editors, one for the Vertex shader
+ and one for the Fragment shader. These editors use CodeMirror's "clike" mode for GLSL syntax.
+
+ * Localizations/en.lproj/localizedStrings.js:
+ * WebInspectorUI.vcxproj/WebInspectorUI.vcxproj:
+ * WebInspectorUI.vcxproj/WebInspectorUI.vcxproj.filters:
+ * UserInterface/Main.html:
+
+ * UserInterface/Controllers/CanvasManager.js:
+ (WI.CanvasManager):
+ (WI.CanvasManager.prototype.canvasRemoved):
+ (WI.CanvasManager.prototype.programCreated):
+ (WI.CanvasManager.prototype.programDeleted):
+ (WI.CanvasManager.prototype._mainResourceDidChange):
+
+ * UserInterface/Models/Collection.js:
+ * UserInterface/Models/Canvas.js:
+ (WI.Canvas.prototype.get shaderProgramCollection)
+
+ * UserInterface/Models/ShaderProgram.js:
+ (WI.ShaderProgram.prototype.requestVertexShaderSource):
+ (WI.ShaderProgram.prototype.requestFragmentShaderSource):
+ (WI.ShaderProgram.prototype._requestShaderSource):
+
+ * UserInterface/Views/CanvasTreeElement.js:
+ (WI.CanvasTreeElement):
+ (WI.CanvasTreeElement.prototype.onattach):
+ (WI.CanvasTreeElement.prototype.ondetach):
+ (WI.CanvasTreeElement.prototype.onpopulate):
+ (WI.CanvasTreeElement.prototype._shaderProgramAdded):
+ (WI.CanvasTreeElement.prototype._shaderProgramRemoved):
+
+ * UserInterface/Views/ShaderProgramTreeElement.js: Added.
+ (WI.ShaderProgramTreeElement):
+
+ * UserInterface/Views/ShaderProgramContentView.js: Added.
+ (WI.ShaderProgramContentView):
+ (WI.ShaderProgramContentView.prototype.shown):
+ (WI.ShaderProgramContentView.prototype.hidden):
+ (WI.ShaderProgramContentView.prototype.closed):
+ (WI.ShaderProgramContentView.prototype.get supportsSave):
+ (WI.ShaderProgramContentView.prototype.get saveData):
+ (WI.ShaderProgramContentView.prototype.get supportsSearch):
+ (WI.ShaderProgramContentView.prototype.get numberOfSearchResults):
+ (WI.ShaderProgramContentView.prototype.get hasPerformedSearch):
+ (WI.ShaderProgramContentView.prototype.set automaticallyRevealFirstSearchResult):
+ (WI.ShaderProgramContentView.prototype.performSearch):
+ (WI.ShaderProgramContentView.prototype.searchCleared):
+ (WI.ShaderProgramContentView.prototype.searchQueryWithSelection):
+ (WI.ShaderProgramContentView.prototype.revealPreviousSearchResult):
+ (WI.ShaderProgramContentView.prototype.revealNextSearchResult):
+ (WI.ShaderProgramContentView.prototype.revealPosition):
+ (WI.ShaderProgramContentView.prototype._editorFocused):
+ (WI.ShaderProgramContentView.prototype._numberOfSearchResultsDidChange):
+ * UserInterface/Views/ShaderProgramContentView.css: Added.
+ (.content-view.shader-program > .text-editor.shader):
+ (body[dir=ltr] .content-view.shader-program > .text-editor.shader.vertex,):
+ (body[dir=ltr] .content-view.shader-program > .text-editor.shader.fragment,):
+ (body[dir=ltr] .content-view.shader-program > .text-editor.shader + .text-editor.shader):
+ (body[dir=rtl] .content-view.shader-program > .text-editor.shader + .text-editor.shader):
+ (.content-view.shader-program > .text-editor.shader > .type-title):
+ (.content-view.shader-program > .text-editor.shader > .CodeMirror):
+
+ * UserInterface/Images/DocumentGL.png: Added.
+ * UserInterface/Images/DocumentGL@2x.png: Added.
+ * UserInterface/Views/ResourceIcons.css:
+ (.shader-program .icon):
+
+ * UserInterface/Base/Main.js:
+ * UserInterface/Views/ContentView.js:
+ (WI.ContentView.createFromRepresentedObject):
+ (WI.ContentView.isViewable):
+ * UserInterface/Views/ResourceSidebarPanel.js:
+ (WI.ResourceSidebarPanel.prototype.matchTreeElementAgainstCustomFilters.match):
+ (WI.ResourceSidebarPanel.prototype.matchTreeElementAgainstCustomFilters):
+ (WI.ResourceSidebarPanel.prototype._treeSelectionDidChange):
+ * UserInterface/Views/ResourcesTabContentView.js:
+ (WI.ResourcesTabContentView.prototype.canShowRepresentedObject):
+ Plumbing for displaying ShaderProgram content.
+
+ * UserInterface/Views/TextEditor.js:
+ (WebInspector.TextEditor):
+ (WebInspector.TextEditor.prototype._editorFocused):
+
+ * Scripts/update-codemirror-resources.rb:
+ * UserInterface/External/CodeMirror/clike.js: Added.
+ Add C-like mode for highlighting GLSL.
+
2017-08-03 Joseph Pecoraro <pecoraro@apple.com>
JSContext Inspector: Scripts sometimes do not show in resources tab
localizedStrings["Format: Short Hex with Alpha"] = "Format: Short Hex with Alpha";
localizedStrings["Forward (%s)"] = "Forward (%s)";
localizedStrings["Fragment"] = "Fragment";
+localizedStrings["Fragment Shader"] = "Fragment Shader";
localizedStrings["Frame %d"] = "Frame %d";
localizedStrings["Frame URL"] = "Frame URL";
localizedStrings["Frames"] = "Frames";
localizedStrings["Probe Sample Recorded"] = "Probe Sample Recorded";
localizedStrings["Probes"] = "Probes";
localizedStrings["Processing Instruction"] = "Processing Instruction";
+localizedStrings["Program %d"] = "Program %d";
localizedStrings["Properties"] = "Properties";
localizedStrings["Property"] = "Property";
localizedStrings["Protocol"] = "Protocol";
localizedStrings["Set to Automatically Continue"] = "Set to Automatically Continue";
localizedStrings["Setter"] = "Setter";
localizedStrings["Settings"] = "Settings";
+localizedStrings["Shader"] = "Shader";
+localizedStrings["Shader Programs"] = "Shader Programs";
localizedStrings["Shadow"] = "Shadow";
localizedStrings["Shadow Content"] = "Shadow Content";
localizedStrings["Shadow Content (%s)"] = "Shadow Content (%s)";
localizedStrings["Variables"] = "Variables";
localizedStrings["Variants"] = "Variants";
localizedStrings["Version"] = "Version";
+localizedStrings["Vertex"] = "Vertex";
+localizedStrings["Vertex Shader"] = "Vertex Shader";
localizedStrings["Vertical"] = "Vertical";
localizedStrings["View variable value"] = "View variable value";
localizedStrings["Visibility"] = "Visibility";
keymap/sublime.js
lib/codemirror.css
lib/codemirror.js
+ mode/clike/clike.js
mode/clojure/clojure.js
mode/coffeescript/coffeescript.js
mode/css/css.js
|| representedObject instanceof WI.Resource
|| representedObject instanceof WI.Script
|| representedObject instanceof WI.CSSStyleSheet
- || representedObject instanceof WI.Canvas)
+ || representedObject instanceof WI.Canvas
+ || representedObject instanceof WI.ShaderProgram)
return WI.ResourcesTabContentView;
// FIXME: Move Content Flows to the Elements tab?
this._canvasIdentifierMap = new Map;
this._shaderProgramIdentifierMap = new Map;
- this._canvasShaderProgramMap = new Map;
if (window.CanvasAgent)
CanvasAgent.enable();
if (!canvas)
return;
- let programs = this._canvasShaderProgramMap.take(canvas);
- if (programs) {
- for (let program of programs) {
- this._shaderProgramIdentifierMap.delete(program.identifier);
- this._dispatchShaderProgramRemoved(program);
- }
+ for (let program of canvas.shaderProgramCollection.items) {
+ this._shaderProgramIdentifierMap.delete(program.identifier);
+ this._dispatchShaderProgramRemoved(program);
}
canvas.frame.canvasCollection.remove(canvas);
let program = new WI.ShaderProgram(programIdentifier, canvas);
this._shaderProgramIdentifierMap.set(program.identifier, program);
- let programs = this._canvasShaderProgramMap.get(canvas);
- if (!programs) {
- programs = [];
- this._canvasShaderProgramMap.set(canvas, programs);
- }
-
- programs.push(program);
+ canvas.shaderProgramCollection.add(program);
this.dispatchEventToListeners(WI.CanvasManager.Event.ShaderProgramAdded, {program});
}
if (!program)
return;
- let programs = this._canvasShaderProgramMap.get(program.canvas);
-
- programs.remove(program);
-
- if (!programs.length)
- this._canvasShaderProgramMap.delete(program.canvas);
+ program.canvas.shaderProgramCollection.remove(program);
this._dispatchShaderProgramRemoved(program);
}
WI.Canvas.resetUniqueDisplayNameNumbers();
this._shaderProgramIdentifierMap.clear();
- this._canvasShaderProgramMap.clear();
if (this._canvasIdentifierMap.size) {
this._canvasIdentifierMap.clear();
--- /dev/null
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
+ mod(require("../../lib/codemirror"));
+ else if (typeof define == "function" && define.amd) // AMD
+ define(["../../lib/codemirror"], mod);
+ else // Plain browser env
+ mod(CodeMirror);
+})(function(CodeMirror) {
+"use strict";
+
+function Context(indented, column, type, info, align, prev) {
+ this.indented = indented;
+ this.column = column;
+ this.type = type;
+ this.info = info;
+ this.align = align;
+ this.prev = prev;
+}
+function pushContext(state, col, type, info) {
+ var indent = state.indented;
+ if (state.context && state.context.type == "statement" && type != "statement")
+ indent = state.context.indented;
+ return state.context = new Context(indent, col, type, info, null, state.context);
+}
+function popContext(state) {
+ var t = state.context.type;
+ if (t == ")" || t == "]" || t == "}")
+ state.indented = state.context.indented;
+ return state.context = state.context.prev;
+}
+
+function typeBefore(stream, state, pos) {
+ if (state.prevToken == "variable" || state.prevToken == "variable-3") return true;
+ if (/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(stream.string.slice(0, pos))) return true;
+ if (state.typeAtEndOfLine && stream.column() == stream.indentation()) return true;
+}
+
+function isTopScope(context) {
+ for (;;) {
+ if (!context || context.type == "top") return true;
+ if (context.type == "}" && context.prev.info != "namespace") return false;
+ context = context.prev;
+ }
+}
+
+CodeMirror.defineMode("clike", function(config, parserConfig) {
+ var indentUnit = config.indentUnit,
+ statementIndentUnit = parserConfig.statementIndentUnit || indentUnit,
+ dontAlignCalls = parserConfig.dontAlignCalls,
+ keywords = parserConfig.keywords || {},
+ types = parserConfig.types || {},
+ builtin = parserConfig.builtin || {},
+ blockKeywords = parserConfig.blockKeywords || {},
+ defKeywords = parserConfig.defKeywords || {},
+ atoms = parserConfig.atoms || {},
+ hooks = parserConfig.hooks || {},
+ multiLineStrings = parserConfig.multiLineStrings,
+ indentStatements = parserConfig.indentStatements !== false,
+ indentSwitch = parserConfig.indentSwitch !== false,
+ namespaceSeparator = parserConfig.namespaceSeparator,
+ isPunctuationChar = parserConfig.isPunctuationChar || /[\[\]{}\(\),;\:\.]/,
+ numberStart = parserConfig.numberStart || /[\d\.]/,
+ number = parserConfig.number || /^(?:0x[a-f\d]+|0b[01]+|(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)(u|ll?|l|f)?/i,
+ isOperatorChar = parserConfig.isOperatorChar || /[+\-*&%=<>!?|\/]/;
+
+ var curPunc, isDefKeyword;
+
+ function tokenBase(stream, state) {
+ var ch = stream.next();
+ if (hooks[ch]) {
+ var result = hooks[ch](stream, state);
+ if (result !== false) return result;
+ }
+ if (ch == '"' || ch == "'") {
+ state.tokenize = tokenString(ch);
+ return state.tokenize(stream, state);
+ }
+ if (isPunctuationChar.test(ch)) {
+ curPunc = ch;
+ return null;
+ }
+ if (numberStart.test(ch)) {
+ stream.backUp(1)
+ if (stream.match(number)) return "number"
+ stream.next()
+ }
+ if (ch == "/") {
+ if (stream.eat("*")) {
+ state.tokenize = tokenComment;
+ return tokenComment(stream, state);
+ }
+ if (stream.eat("/")) {
+ stream.skipToEnd();
+ return "comment";
+ }
+ }
+ if (isOperatorChar.test(ch)) {
+ while (!stream.match(/^\/[\/*]/, false) && stream.eat(isOperatorChar)) {}
+ return "operator";
+ }
+ stream.eatWhile(/[\w\$_\xa1-\uffff]/);
+ if (namespaceSeparator) while (stream.match(namespaceSeparator))
+ stream.eatWhile(/[\w\$_\xa1-\uffff]/);
+
+ var cur = stream.current();
+ if (contains(keywords, cur)) {
+ if (contains(blockKeywords, cur)) curPunc = "newstatement";
+ if (contains(defKeywords, cur)) isDefKeyword = true;
+ return "keyword";
+ }
+ if (contains(types, cur)) return "variable-3";
+ if (contains(builtin, cur)) {
+ if (contains(blockKeywords, cur)) curPunc = "newstatement";
+ return "builtin";
+ }
+ if (contains(atoms, cur)) return "atom";
+ return "variable";
+ }
+
+ function tokenString(quote) {
+ return function(stream, state) {
+ var escaped = false, next, end = false;
+ while ((next = stream.next()) != null) {
+ if (next == quote && !escaped) {end = true; break;}
+ escaped = !escaped && next == "\\";
+ }
+ if (end || !(escaped || multiLineStrings))
+ state.tokenize = null;
+ return "string";
+ };
+ }
+
+ function tokenComment(stream, state) {
+ var maybeEnd = false, ch;
+ while (ch = stream.next()) {
+ if (ch == "/" && maybeEnd) {
+ state.tokenize = null;
+ break;
+ }
+ maybeEnd = (ch == "*");
+ }
+ return "comment";
+ }
+
+ function maybeEOL(stream, state) {
+ if (parserConfig.typeFirstDefinitions && stream.eol() && isTopScope(state.context))
+ state.typeAtEndOfLine = typeBefore(stream, state, stream.pos)
+ }
+
+ // Interface
+
+ return {
+ startState: function(basecolumn) {
+ return {
+ tokenize: null,
+ context: new Context((basecolumn || 0) - indentUnit, 0, "top", null, false),
+ indented: 0,
+ startOfLine: true,
+ prevToken: null
+ };
+ },
+
+ token: function(stream, state) {
+ var ctx = state.context;
+ if (stream.sol()) {
+ if (ctx.align == null) ctx.align = false;
+ state.indented = stream.indentation();
+ state.startOfLine = true;
+ }
+ if (stream.eatSpace()) { maybeEOL(stream, state); return null; }
+ curPunc = isDefKeyword = null;
+ var style = (state.tokenize || tokenBase)(stream, state);
+ if (style == "comment" || style == "meta") return style;
+ if (ctx.align == null) ctx.align = true;
+
+ if (curPunc == ";" || curPunc == ":" || (curPunc == "," && stream.match(/^\s*(?:\/\/.*)?$/, false)))
+ while (state.context.type == "statement") popContext(state);
+ else if (curPunc == "{") pushContext(state, stream.column(), "}");
+ else if (curPunc == "[") pushContext(state, stream.column(), "]");
+ else if (curPunc == "(") pushContext(state, stream.column(), ")");
+ else if (curPunc == "}") {
+ while (ctx.type == "statement") ctx = popContext(state);
+ if (ctx.type == "}") ctx = popContext(state);
+ while (ctx.type == "statement") ctx = popContext(state);
+ }
+ else if (curPunc == ctx.type) popContext(state);
+ else if (indentStatements &&
+ (((ctx.type == "}" || ctx.type == "top") && curPunc != ";") ||
+ (ctx.type == "statement" && curPunc == "newstatement"))) {
+ pushContext(state, stream.column(), "statement", stream.current());
+ }
+
+ if (style == "variable" &&
+ ((state.prevToken == "def" ||
+ (parserConfig.typeFirstDefinitions && typeBefore(stream, state, stream.start) &&
+ isTopScope(state.context) && stream.match(/^\s*\(/, false)))))
+ style = "def";
+
+ if (hooks.token) {
+ var result = hooks.token(stream, state, style);
+ if (result !== undefined) style = result;
+ }
+
+ if (style == "def" && parserConfig.styleDefs === false) style = "variable";
+
+ state.startOfLine = false;
+ state.prevToken = isDefKeyword ? "def" : style || curPunc;
+ maybeEOL(stream, state);
+ return style;
+ },
+
+ indent: function(state, textAfter) {
+ if (state.tokenize != tokenBase && state.tokenize != null || state.typeAtEndOfLine) return CodeMirror.Pass;
+ var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
+ if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev;
+ if (parserConfig.dontIndentStatements)
+ while (ctx.type == "statement" && parserConfig.dontIndentStatements.test(ctx.info))
+ ctx = ctx.prev
+ if (hooks.indent) {
+ var hook = hooks.indent(state, ctx, textAfter);
+ if (typeof hook == "number") return hook
+ }
+ var closing = firstChar == ctx.type;
+ var switchBlock = ctx.prev && ctx.prev.info == "switch";
+ if (parserConfig.allmanIndentation && /[{(]/.test(firstChar)) {
+ while (ctx.type != "top" && ctx.type != "}") ctx = ctx.prev
+ return ctx.indented
+ }
+ if (ctx.type == "statement")
+ return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit);
+ if (ctx.align && (!dontAlignCalls || ctx.type != ")"))
+ return ctx.column + (closing ? 0 : 1);
+ if (ctx.type == ")" && !closing)
+ return ctx.indented + statementIndentUnit;
+
+ return ctx.indented + (closing ? 0 : indentUnit) +
+ (!closing && switchBlock && !/^(?:case|default)\b/.test(textAfter) ? indentUnit : 0);
+ },
+
+ electricInput: indentSwitch ? /^\s*(?:case .*?:|default:|\{\}?|\})$/ : /^\s*[{}]$/,
+ blockCommentStart: "/*",
+ blockCommentEnd: "*/",
+ lineComment: "//",
+ fold: "brace"
+ };
+});
+
+ function words(str) {
+ var obj = {}, words = str.split(" ");
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
+ return obj;
+ }
+ function contains(words, word) {
+ if (typeof words === "function") {
+ return words(word);
+ } else {
+ return words.propertyIsEnumerable(word);
+ }
+ }
+ var cKeywords = "auto if break case register continue return default do sizeof " +
+ "static else struct switch extern typedef union for goto while enum const volatile";
+ var cTypes = "int long char short double float unsigned signed void size_t ptrdiff_t";
+
+ function cppHook(stream, state) {
+ if (!state.startOfLine) return false
+ for (var ch, next = null; ch = stream.peek();) {
+ if (ch == "\\" && stream.match(/^.$/)) {
+ next = cppHook
+ break
+ } else if (ch == "/" && stream.match(/^\/[\/\*]/, false)) {
+ break
+ }
+ stream.next()
+ }
+ state.tokenize = next
+ return "meta"
+ }
+
+ function pointerHook(_stream, state) {
+ if (state.prevToken == "variable-3") return "variable-3";
+ return false;
+ }
+
+ function cpp14Literal(stream) {
+ stream.eatWhile(/[\w\.']/);
+ return "number";
+ }
+
+ function cpp11StringHook(stream, state) {
+ stream.backUp(1);
+ // Raw strings.
+ if (stream.match(/(R|u8R|uR|UR|LR)/)) {
+ var match = stream.match(/"([^\s\\()]{0,16})\(/);
+ if (!match) {
+ return false;
+ }
+ state.cpp11RawStringDelim = match[1];
+ state.tokenize = tokenRawString;
+ return tokenRawString(stream, state);
+ }
+ // Unicode strings/chars.
+ if (stream.match(/(u8|u|U|L)/)) {
+ if (stream.match(/["']/, /* eat */ false)) {
+ return "string";
+ }
+ return false;
+ }
+ // Ignore this hook.
+ stream.next();
+ return false;
+ }
+
+ function cppLooksLikeConstructor(word) {
+ var lastTwo = /(\w+)::(\w+)$/.exec(word);
+ return lastTwo && lastTwo[1] == lastTwo[2];
+ }
+
+ // C#-style strings where "" escapes a quote.
+ function tokenAtString(stream, state) {
+ var next;
+ while ((next = stream.next()) != null) {
+ if (next == '"' && !stream.eat('"')) {
+ state.tokenize = null;
+ break;
+ }
+ }
+ return "string";
+ }
+
+ // C++11 raw string literal is <prefix>"<delim>( anything )<delim>", where
+ // <delim> can be a string up to 16 characters long.
+ function tokenRawString(stream, state) {
+ // Escape characters that have special regex meanings.
+ var delim = state.cpp11RawStringDelim.replace(/[^\w\s]/g, '\\$&');
+ var match = stream.match(new RegExp(".*?\\)" + delim + '"'));
+ if (match)
+ state.tokenize = null;
+ else
+ stream.skipToEnd();
+ return "string";
+ }
+
+ function def(mimes, mode) {
+ if (typeof mimes == "string") mimes = [mimes];
+ var words = [];
+ function add(obj) {
+ if (obj) for (var prop in obj) if (obj.hasOwnProperty(prop))
+ words.push(prop);
+ }
+ add(mode.keywords);
+ add(mode.types);
+ add(mode.builtin);
+ add(mode.atoms);
+ if (words.length) {
+ mode.helperType = mimes[0];
+ CodeMirror.registerHelper("hintWords", mimes[0], words);
+ }
+
+ for (var i = 0; i < mimes.length; ++i)
+ CodeMirror.defineMIME(mimes[i], mode);
+ }
+
+ def(["text/x-csrc", "text/x-c", "text/x-chdr"], {
+ name: "clike",
+ keywords: words(cKeywords),
+ types: words(cTypes + " bool _Complex _Bool float_t double_t intptr_t intmax_t " +
+ "int8_t int16_t int32_t int64_t uintptr_t uintmax_t uint8_t uint16_t " +
+ "uint32_t uint64_t"),
+ blockKeywords: words("case do else for if switch while struct"),
+ defKeywords: words("struct"),
+ typeFirstDefinitions: true,
+ atoms: words("null true false"),
+ hooks: {"#": cppHook, "*": pointerHook},
+ modeProps: {fold: ["brace", "include"]}
+ });
+
+ def(["text/x-c++src", "text/x-c++hdr"], {
+ name: "clike",
+ keywords: words(cKeywords + " asm dynamic_cast namespace reinterpret_cast try explicit new " +
+ "static_cast typeid catch operator template typename class friend private " +
+ "this using const_cast inline public throw virtual delete mutable protected " +
+ "alignas alignof constexpr decltype nullptr noexcept thread_local final " +
+ "static_assert override"),
+ types: words(cTypes + " bool wchar_t"),
+ blockKeywords: words("catch class do else finally for if struct switch try while"),
+ defKeywords: words("class namespace struct enum union"),
+ typeFirstDefinitions: true,
+ atoms: words("true false null"),
+ dontIndentStatements: /^template$/,
+ hooks: {
+ "#": cppHook,
+ "*": pointerHook,
+ "u": cpp11StringHook,
+ "U": cpp11StringHook,
+ "L": cpp11StringHook,
+ "R": cpp11StringHook,
+ "0": cpp14Literal,
+ "1": cpp14Literal,
+ "2": cpp14Literal,
+ "3": cpp14Literal,
+ "4": cpp14Literal,
+ "5": cpp14Literal,
+ "6": cpp14Literal,
+ "7": cpp14Literal,
+ "8": cpp14Literal,
+ "9": cpp14Literal,
+ token: function(stream, state, style) {
+ if (style == "variable" && stream.peek() == "(" &&
+ (state.prevToken == ";" || state.prevToken == null ||
+ state.prevToken == "}") &&
+ cppLooksLikeConstructor(stream.current()))
+ return "def";
+ }
+ },
+ namespaceSeparator: "::",
+ modeProps: {fold: ["brace", "include"]}
+ });
+
+ def("text/x-java", {
+ name: "clike",
+ keywords: words("abstract assert break case catch class const continue default " +
+ "do else enum extends final finally float for goto if implements import " +
+ "instanceof interface native new package private protected public " +
+ "return static strictfp super switch synchronized this throw throws transient " +
+ "try volatile while"),
+ types: words("byte short int long float double boolean char void Boolean Byte Character Double Float " +
+ "Integer Long Number Object Short String StringBuffer StringBuilder Void"),
+ blockKeywords: words("catch class do else finally for if switch try while"),
+ defKeywords: words("class interface package enum"),
+ typeFirstDefinitions: true,
+ atoms: words("true false null"),
+ number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+\.?\d*|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,
+ hooks: {
+ "@": function(stream) {
+ stream.eatWhile(/[\w\$_]/);
+ return "meta";
+ }
+ },
+ modeProps: {fold: ["brace", "import"]}
+ });
+
+ def("text/x-csharp", {
+ name: "clike",
+ keywords: words("abstract as async await base break case catch checked class const continue" +
+ " default delegate do else enum event explicit extern finally fixed for" +
+ " foreach goto if implicit in interface internal is lock namespace new" +
+ " operator out override params private protected public readonly ref return sealed" +
+ " sizeof stackalloc static struct switch this throw try typeof unchecked" +
+ " unsafe using virtual void volatile while add alias ascending descending dynamic from get" +
+ " global group into join let orderby partial remove select set value var yield"),
+ types: words("Action Boolean Byte Char DateTime DateTimeOffset Decimal Double Func" +
+ " Guid Int16 Int32 Int64 Object SByte Single String Task TimeSpan UInt16 UInt32" +
+ " UInt64 bool byte char decimal double short int long object" +
+ " sbyte float string ushort uint ulong"),
+ blockKeywords: words("catch class do else finally for foreach if struct switch try while"),
+ defKeywords: words("class interface namespace struct var"),
+ typeFirstDefinitions: true,
+ atoms: words("true false null"),
+ hooks: {
+ "@": function(stream, state) {
+ if (stream.eat('"')) {
+ state.tokenize = tokenAtString;
+ return tokenAtString(stream, state);
+ }
+ stream.eatWhile(/[\w\$_]/);
+ return "meta";
+ }
+ }
+ });
+
+ function tokenTripleString(stream, state) {
+ var escaped = false;
+ while (!stream.eol()) {
+ if (!escaped && stream.match('"""')) {
+ state.tokenize = null;
+ break;
+ }
+ escaped = stream.next() == "\\" && !escaped;
+ }
+ return "string";
+ }
+
+ def("text/x-scala", {
+ name: "clike",
+ keywords: words(
+
+ /* scala */
+ "abstract case catch class def do else extends final finally for forSome if " +
+ "implicit import lazy match new null object override package private protected return " +
+ "sealed super this throw trait try type val var while with yield _ : = => <- <: " +
+ "<% >: # @ " +
+
+ /* package scala */
+ "assert assume require print println printf readLine readBoolean readByte readShort " +
+ "readChar readInt readLong readFloat readDouble " +
+
+ ":: #:: "
+ ),
+ types: words(
+ "AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " +
+ "Enumeration Equiv Error Exception Fractional Function IndexedSeq Int Integral Iterable " +
+ "Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " +
+ "Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " +
+ "StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector " +
+
+ /* package java.lang */
+ "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
+ "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
+ "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
+ "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"
+ ),
+ multiLineStrings: true,
+ blockKeywords: words("catch class do else finally for forSome if match switch try while"),
+ defKeywords: words("class def object package trait type val var"),
+ atoms: words("true false null"),
+ indentStatements: false,
+ indentSwitch: false,
+ hooks: {
+ "@": function(stream) {
+ stream.eatWhile(/[\w\$_]/);
+ return "meta";
+ },
+ '"': function(stream, state) {
+ if (!stream.match('""')) return false;
+ state.tokenize = tokenTripleString;
+ return state.tokenize(stream, state);
+ },
+ "'": function(stream) {
+ stream.eatWhile(/[\w\$_\xa1-\uffff]/);
+ return "atom";
+ },
+ "=": function(stream, state) {
+ var cx = state.context
+ if (cx.type == "}" && cx.align && stream.eat(">")) {
+ state.context = new Context(cx.indented, cx.column, cx.type, cx.info, null, cx.prev)
+ return "operator"
+ } else {
+ return false
+ }
+ }
+ },
+ modeProps: {closeBrackets: {triples: '"'}}
+ });
+
+ function tokenKotlinString(tripleString){
+ return function (stream, state) {
+ var escaped = false, next, end = false;
+ while (!stream.eol()) {
+ if (!tripleString && !escaped && stream.match('"') ) {end = true; break;}
+ if (tripleString && stream.match('"""')) {end = true; break;}
+ next = stream.next();
+ if(!escaped && next == "$" && stream.match('{'))
+ stream.skipTo("}");
+ escaped = !escaped && next == "\\" && !tripleString;
+ }
+ if (end || !tripleString)
+ state.tokenize = null;
+ return "string";
+ }
+ }
+
+ def("text/x-kotlin", {
+ name: "clike",
+ keywords: words(
+ /*keywords*/
+ "package as typealias class interface this super val " +
+ "var fun for is in This throw return " +
+ "break continue object if else while do try when !in !is as? " +
+
+ /*soft keywords*/
+ "file import where by get set abstract enum open inner override private public internal " +
+ "protected catch finally out final vararg reified dynamic companion constructor init " +
+ "sealed field property receiver param sparam lateinit data inline noinline tailrec " +
+ "external annotation crossinline const operator infix"
+ ),
+ types: words(
+ /* package java.lang */
+ "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
+ "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
+ "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
+ "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"
+ ),
+ intendSwitch: false,
+ indentStatements: false,
+ multiLineStrings: true,
+ blockKeywords: words("catch class do else finally for if where try while enum"),
+ defKeywords: words("class val var object package interface fun"),
+ atoms: words("true false null this"),
+ hooks: {
+ '"': function(stream, state) {
+ state.tokenize = tokenKotlinString(stream.match('""'));
+ return state.tokenize(stream, state);
+ }
+ },
+ modeProps: {closeBrackets: {triples: '"'}}
+ });
+
+ def(["x-shader/x-vertex", "x-shader/x-fragment"], {
+ name: "clike",
+ keywords: words("sampler1D sampler2D sampler3D samplerCube " +
+ "sampler1DShadow sampler2DShadow " +
+ "const attribute uniform varying " +
+ "break continue discard return " +
+ "for while do if else struct " +
+ "in out inout"),
+ types: words("float int bool void " +
+ "vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 " +
+ "mat2 mat3 mat4"),
+ blockKeywords: words("for while do if else struct"),
+ builtin: words("radians degrees sin cos tan asin acos atan " +
+ "pow exp log exp2 sqrt inversesqrt " +
+ "abs sign floor ceil fract mod min max clamp mix step smoothstep " +
+ "length distance dot cross normalize ftransform faceforward " +
+ "reflect refract matrixCompMult " +
+ "lessThan lessThanEqual greaterThan greaterThanEqual " +
+ "equal notEqual any all not " +
+ "texture1D texture1DProj texture1DLod texture1DProjLod " +
+ "texture2D texture2DProj texture2DLod texture2DProjLod " +
+ "texture3D texture3DProj texture3DLod texture3DProjLod " +
+ "textureCube textureCubeLod " +
+ "shadow1D shadow2D shadow1DProj shadow2DProj " +
+ "shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod " +
+ "dFdx dFdy fwidth " +
+ "noise1 noise2 noise3 noise4"),
+ atoms: words("true false " +
+ "gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex " +
+ "gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 " +
+ "gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 " +
+ "gl_FogCoord gl_PointCoord " +
+ "gl_Position gl_PointSize gl_ClipVertex " +
+ "gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor " +
+ "gl_TexCoord gl_FogFragCoord " +
+ "gl_FragCoord gl_FrontFacing " +
+ "gl_FragData gl_FragDepth " +
+ "gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix " +
+ "gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse " +
+ "gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse " +
+ "gl_TexureMatrixTranspose gl_ModelViewMatrixInverseTranspose " +
+ "gl_ProjectionMatrixInverseTranspose " +
+ "gl_ModelViewProjectionMatrixInverseTranspose " +
+ "gl_TextureMatrixInverseTranspose " +
+ "gl_NormalScale gl_DepthRange gl_ClipPlane " +
+ "gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel " +
+ "gl_FrontLightModelProduct gl_BackLightModelProduct " +
+ "gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ " +
+ "gl_FogParameters " +
+ "gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords " +
+ "gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats " +
+ "gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits " +
+ "gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits " +
+ "gl_MaxDrawBuffers"),
+ indentSwitch: false,
+ hooks: {"#": cppHook},
+ modeProps: {fold: ["brace", "include"]}
+ });
+
+ def("text/x-nesc", {
+ name: "clike",
+ keywords: words(cKeywords + "as atomic async call command component components configuration event generic " +
+ "implementation includes interface module new norace nx_struct nx_union post provides " +
+ "signal task uses abstract extends"),
+ types: words(cTypes),
+ blockKeywords: words("case do else for if switch while struct"),
+ atoms: words("null true false"),
+ hooks: {"#": cppHook},
+ modeProps: {fold: ["brace", "include"]}
+ });
+
+ def("text/x-objectivec", {
+ name: "clike",
+ keywords: words(cKeywords + "inline restrict _Bool _Complex _Imaginary BOOL Class bycopy byref id IMP in " +
+ "inout nil oneway out Protocol SEL self super atomic nonatomic retain copy readwrite readonly"),
+ types: words(cTypes),
+ atoms: words("YES NO NULL NILL ON OFF true false"),
+ hooks: {
+ "@": function(stream) {
+ stream.eatWhile(/[\w\$]/);
+ return "keyword";
+ },
+ "#": cppHook,
+ indent: function(_state, ctx, textAfter) {
+ if (ctx.type == "statement" && /^@\w/.test(textAfter)) return ctx.indented
+ }
+ },
+ modeProps: {fold: "brace"}
+ });
+
+ def("text/x-squirrel", {
+ name: "clike",
+ keywords: words("base break clone continue const default delete enum extends function in class" +
+ " foreach local resume return this throw typeof yield constructor instanceof static"),
+ types: words(cTypes),
+ blockKeywords: words("case catch class else for foreach if switch try while"),
+ defKeywords: words("function local class"),
+ typeFirstDefinitions: true,
+ atoms: words("true false null"),
+ hooks: {"#": cppHook},
+ modeProps: {fold: ["brace", "include"]}
+ });
+
+ // Ceylon Strings need to deal with interpolation
+ var stringTokenizer = null;
+ function tokenCeylonString(type) {
+ return function(stream, state) {
+ var escaped = false, next, end = false;
+ while (!stream.eol()) {
+ if (!escaped && stream.match('"') &&
+ (type == "single" || stream.match('""'))) {
+ end = true;
+ break;
+ }
+ if (!escaped && stream.match('``')) {
+ stringTokenizer = tokenCeylonString(type);
+ end = true;
+ break;
+ }
+ next = stream.next();
+ escaped = type == "single" && !escaped && next == "\\";
+ }
+ if (end)
+ state.tokenize = null;
+ return "string";
+ }
+ }
+
+ def("text/x-ceylon", {
+ name: "clike",
+ keywords: words("abstracts alias assembly assert assign break case catch class continue dynamic else" +
+ " exists extends finally for function given if import in interface is let module new" +
+ " nonempty object of out outer package return satisfies super switch then this throw" +
+ " try value void while"),
+ types: function(word) {
+ // In Ceylon all identifiers that start with an uppercase are types
+ var first = word.charAt(0);
+ return (first === first.toUpperCase() && first !== first.toLowerCase());
+ },
+ blockKeywords: words("case catch class dynamic else finally for function if interface module new object switch try while"),
+ defKeywords: words("class dynamic function interface module object package value"),
+ builtin: words("abstract actual aliased annotation by default deprecated doc final formal late license" +
+ " native optional sealed see serializable shared suppressWarnings tagged throws variable"),
+ isPunctuationChar: /[\[\]{}\(\),;\:\.`]/,
+ isOperatorChar: /[+\-*&%=<>!?|^~:\/]/,
+ numberStart: /[\d#$]/,
+ number: /^(?:#[\da-fA-F_]+|\$[01_]+|[\d_]+[kMGTPmunpf]?|[\d_]+\.[\d_]+(?:[eE][-+]?\d+|[kMGTPmunpf]|)|)/i,
+ multiLineStrings: true,
+ typeFirstDefinitions: true,
+ atoms: words("true false null larger smaller equal empty finished"),
+ indentSwitch: false,
+ styleDefs: false,
+ hooks: {
+ "@": function(stream) {
+ stream.eatWhile(/[\w\$_]/);
+ return "meta";
+ },
+ '"': function(stream, state) {
+ state.tokenize = tokenCeylonString(stream.match('""') ? "triple" : "single");
+ return state.tokenize(stream, state);
+ },
+ '`': function(stream, state) {
+ if (!stringTokenizer || !stream.match('`')) return false;
+ state.tokenize = stringTokenizer;
+ stringTokenizer = null;
+ return state.tokenize(stream, state);
+ },
+ "'": function(stream) {
+ stream.eatWhile(/[\w\$_\xa1-\uffff]/);
+ return "atom";
+ },
+ token: function(_stream, state, style) {
+ if ((style == "variable" || style == "variable-3") &&
+ state.prevToken == ".") {
+ return "variable-2";
+ }
+ }
+ },
+ modeProps: {
+ fold: ["brace", "import"],
+ closeBrackets: {triples: '"'}
+ }
+ });
+
+});
<link rel="stylesheet" href="Views/SearchIcons.css">
<link rel="stylesheet" href="Views/SearchSidebarPanel.css">
<link rel="stylesheet" href="Views/SettingsTabContentView.css">
+ <link rel="stylesheet" href="Views/ShaderProgramContentView.css">
<link rel="stylesheet" href="Views/Sidebar.css">
<link rel="stylesheet" href="Views/SidebarPanel.css">
<link rel="stylesheet" href="Views/Slider.css">
<script src="External/CodeMirror/codemirror.js"></script>
+ <script src="External/CodeMirror/clike.js"></script>
<script src="External/CodeMirror/clojure.js"></script>
<script src="External/CodeMirror/closebrackets.js"></script>
<script src="External/CodeMirror/coffeescript.js"></script>
<script src="Views/SearchBar.js"></script>
<script src="Views/SearchResultTreeElement.js"></script>
<script src="Views/SearchSidebarPanel.js"></script>
+ <script src="Views/ShaderProgramContentView.js"></script>
+ <script src="Views/ShaderProgramTreeElement.js"></script>
<script src="Views/Sidebar.js"></script>
<script src="Views/Slider.js"></script>
<script src="Views/SoftContextMenu.js"></script>
this._memoryCost = memoryCost || NaN;
this._cssCanvasClientNodes = null;
+ this._shaderProgramCollection = new WI.Collection(WI.Collection.TypeVerifier.ShaderProgram);
this._nextShaderProgramDisplayNumber = 1;
}
get frame() { return this._frame; }
get cssCanvasName() { return this._cssCanvasName; }
get contextAttributes() { return this._contextAttributes; }
+ get shaderProgramCollection() { return this._shaderProgramCollection; }
get memoryCost()
{
Script: (object) => object instanceof WI.Script,
CSSStyleSheet: (object) => object instanceof WI.CSSStyleSheet,
Canvas: (object) => object instanceof WI.Canvas,
+ ShaderProgram: (object) => object instanceof WI.ShaderProgram,
};
{
return WI.UIString("Program %d").format(this._uniqueDisplayNumber);
}
+
+ requestVertexShaderSource(callback)
+ {
+ this._requestShaderSource(CanvasAgent.ShaderType.Vertex, callback);
+ }
+
+ requestFragmentShaderSource(callback)
+ {
+ this._requestShaderSource(CanvasAgent.ShaderType.Fragment, callback);
+ }
+
+ // Private
+
+ _requestShaderSource(shaderType, callback)
+ {
+ CanvasAgent.requestShaderSource(this._identifier, shaderType, (error, content) => {
+ if (error) {
+ callback(null);
+ return;
+ }
+
+ callback(content);
+ });
+ }
+};
+
+WI.ShaderProgram.ShaderType = {
+ Fragment: "shader-type-fragment",
+ Vertex: "shader-type-vertex",
};
WI.ShaderProgram.Event = {
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-WI.CanvasTreeElement = class CanvasTreeElement extends WI.GeneralTreeElement
+WI.CanvasTreeElement = class CanvasTreeElement extends WI.FolderizedTreeElement
{
constructor(representedObject)
{
const subtitle = null;
super(["canvas", representedObject.contextType], representedObject.displayName, subtitle, representedObject);
+
+ this.registerFolderizeSettings("shader-programs", WI.UIString("Shader Programs"), this.representedObject.shaderProgramCollection, WI.ShaderProgramTreeElement);
}
// Protected
{
super.onattach();
+ this.representedObject.shaderProgramCollection.addEventListener(WI.Collection.Event.ItemAdded, this._shaderProgramAdded, this);
+ this.representedObject.shaderProgramCollection.addEventListener(WI.Collection.Event.ItemRemoved, this._shaderProgramRemoved, this);
+
this.element.addEventListener("mouseover", this._handleMouseOver.bind(this));
this.element.addEventListener("mouseout", this._handleMouseOut.bind(this));
+
+ this.onpopulate();
+ }
+
+ ondetach()
+ {
+ this.representedObject.shaderProgramCollection.removeEventListener(WI.Collection.Event.ItemAdded, this._shaderProgramAdded, this);
+ this.representedObject.shaderProgramCollection.removeEventListener(WI.Collection.Event.ItemRemoved, this._shaderProgramRemoved, this);
+
+ super.ondetach();
+ }
+
+ onpopulate()
+ {
+ super.onpopulate();
+
+ if (this.children.length && !this.shouldRefreshChildren)
+ return;
+
+ this.shouldRefreshChildren = false;
+
+ this.removeChildren();
+
+ for (let program of this.representedObject.shaderProgramCollection.items)
+ this.addChildForRepresentedObject(program);
}
populateContextMenu(contextMenu, event)
// Private
+ _shaderProgramAdded(event)
+ {
+ this.addRepresentedObjectToNewChildQueue(event.data.item);
+ }
+
+ _shaderProgramRemoved(event)
+ {
+ this.removeChildForRepresentedObject(event.data.item);
+ }
+
_handleMouseOver(event)
{
if (this.representedObject.cssCanvasName) {
if (representedObject instanceof WI.Canvas)
return new WI.CanvasContentView(representedObject, extraArguments);
+ if (representedObject instanceof WI.ShaderProgram)
+ return new WI.ShaderProgramContentView(representedObject, extraArguments);
+
if (representedObject instanceof WI.TimelineRecording)
return new WI.TimelineRecordingContentView(representedObject, extraArguments);
return true;
if (representedObject instanceof WI.Canvas)
return true;
+ if (representedObject instanceof WI.ShaderProgram)
+ return true;
if (representedObject instanceof WI.TimelineRecording)
return true;
if (representedObject instanceof WI.Timeline)
content: url(../Images/Canvas3D.svg);
}
+.shader-program .icon {
+ content: image-set(url(../Images/DocumentGL.png) 1x, url(../Images/DocumentGL@2x.png) 2x);
+}
+
.large .resource-icon .icon {
content: image-set(url(../Images/DocumentGenericLarge.png) 1x, url(../Images/DocumentGenericLarge@2x.png) 2x);
}
if (treeElement instanceof WI.ScriptTreeElement)
return selectedScopeBarItem[WI.ResourceSidebarPanel.ResourceTypeSymbol] === WI.Resource.Type.Script;
- if (treeElement instanceof WI.CanvasTreeElement)
+ if (treeElement instanceof WI.CanvasTreeElement || treeElement instanceof WI.ShaderProgramTreeElement)
return selectedScopeBarItem[WI.ResourceSidebarPanel.ResourceTypeSymbol] === WI.Canvas.ResourceSidebarType;
if (treeElement instanceof WI.CSSStyleSheetTreeElement)
|| treeElement instanceof WI.ScriptTreeElement
|| treeElement instanceof WI.CSSStyleSheetTreeElement
|| treeElement instanceof WI.ContentFlowTreeElement
- || treeElement instanceof WI.CanvasTreeElement) {
+ || treeElement instanceof WI.CanvasTreeElement
+ || treeElement instanceof WI.ShaderProgramTreeElement) {
const cookie = null;
const options = {
ignoreNetworkTab: true,
|| representedObject instanceof WI.CSSStyleSheet
|| representedObject instanceof WI.ContentFlow
|| representedObject instanceof WI.Canvas
+ || representedObject instanceof WI.ShaderProgram
|| representedObject instanceof WI.Collection;
}
};
--- /dev/null
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.content-view.shader-program > .text-editor.shader {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+
+ --border-start-style: 1px solid lightgrey;;
+}
+
+body[dir=ltr] .content-view.shader-program > .text-editor.shader.vertex,
+body[dir=rtl] .content-view.shader-program > .text-editor.shader.fragment {
+ width: calc(50% - 1px);
+ left: 0;
+}
+
+body[dir=ltr] .content-view.shader-program > .text-editor.shader.fragment,
+body[dir=rtl] .content-view.shader-program > .text-editor.shader.vertex {
+ width: calc(50% + 1px);
+ right: 0;
+}
+
+body[dir=ltr] .content-view.shader-program > .text-editor.shader + .text-editor.shader {
+ border-left: var(--border-start-style);
+}
+
+body[dir=rtl] .content-view.shader-program > .text-editor.shader + .text-editor.shader {
+ border-right: var(--border-start-style);
+}
+
+.content-view.shader-program > .text-editor.shader > .type-title {
+ padding: 2px 4px;
+ background-color: hsl(0, 0%, 95%);
+ border-bottom: 1px solid lightgrey;
+}
+
+.content-view.shader-program > .text-editor.shader > .CodeMirror {
+ top: 18px;
+}
--- /dev/null
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WI.ShaderProgramContentView = class ShaderProgramContentView extends WI.ContentView
+{
+ constructor(shaderProgram)
+ {
+ console.assert(shaderProgram instanceof WI.ShaderProgram);
+
+ super(shaderProgram);
+
+ this.element.classList.add("shader-program");
+
+ let createEditor = (shaderType) => {
+ let textEditor = new WI.TextEditor;
+ textEditor.addEventListener(WI.TextEditor.Event.Focused, this._editorFocused, this);
+ textEditor.addEventListener(WI.TextEditor.Event.NumberOfSearchResultsDidChange, this._numberOfSearchResultsDidChange, this);
+ textEditor.element.classList.add("shader");
+
+ let shaderTypeContainer = textEditor.element.insertAdjacentElement("afterbegin", document.createElement("div"));
+ shaderTypeContainer.classList.add("type-title");
+
+ switch (shaderType) {
+ case WI.ShaderProgram.ShaderType.Vertex:
+ shaderTypeContainer.textContent = WI.UIString("Vertex Shader");
+ textEditor.mimeType = "x-shader/x-vertex";
+ textEditor.element.classList.add("vertex");
+ break;
+
+ case WI.ShaderProgram.ShaderType.Fragment:
+ shaderTypeContainer.textContent = WI.UIString("Fragment Shader");
+ textEditor.mimeType = "x-shader/x-fragment";
+ textEditor.element.classList.add("fragment");
+ break;
+ }
+
+ this.addSubview(textEditor);
+ return textEditor;
+ };
+
+ this._vertexEditor = createEditor(WI.ShaderProgram.ShaderType.Vertex);
+ this._fragmentEditor = createEditor(WI.ShaderProgram.ShaderType.Fragment);
+ this._lastActiveEditor = this._vertexEditor;
+ }
+
+ // Protected
+
+ shown()
+ {
+ super.shown();
+
+ this._vertexEditor.shown();
+ this._fragmentEditor.shown();
+
+ this.representedObject.requestVertexShaderSource((content) => {
+ this._vertexEditor.string = content || "";
+ });
+
+ this.representedObject.requestFragmentShaderSource((content) => {
+ this._fragmentEditor.string = content || "";
+ });
+ }
+
+ hidden()
+ {
+ this._vertexEditor.hidden();
+ this._fragmentEditor.hidden();
+
+ super.hidden();
+ }
+
+ closed()
+ {
+ this._vertexEditor.close();
+ this._fragmentEditor.close();
+
+ super.closed();
+ }
+
+ get supportsSave()
+ {
+ return true;
+ }
+
+ get saveData()
+ {
+ let filename = WI.UIString("Shader");
+ if (this._lastActiveEditor === this._vertexEditor)
+ filename = WI.UIString("Vertex");
+ else if (this._lastActiveEditor === this._fragmentEditor)
+ filename = WI.UIString("Fragment");
+
+ return {
+ url: `web-inspector:///${filename}.glsl`,
+ content: this._lastActiveEditor.string,
+ forceSaveAs: true,
+ };
+ }
+
+ get supportsSearch()
+ {
+ return true;
+ }
+
+ get numberOfSearchResults()
+ {
+ return this._lastActiveEditor.numberOfSearchResults;
+ }
+
+ get hasPerformedSearch()
+ {
+ return this._lastActiveEditor.currentSearchQuery !== null;
+ }
+
+ set automaticallyRevealFirstSearchResult(reveal)
+ {
+ this._lastActiveEditor.automaticallyRevealFirstSearchResult = reveal;
+ }
+
+ performSearch(query)
+ {
+ this._lastActiveEditor.performSearch(query);
+ }
+
+ searchCleared()
+ {
+ this._lastActiveEditor.searchCleared();
+ }
+
+ searchQueryWithSelection()
+ {
+ return this._lastActiveEditor.searchQueryWithSelection();
+ }
+
+ revealPreviousSearchResult(changeFocus)
+ {
+ this._lastActiveEditor.revealPreviousSearchResult(changeFocus);
+ }
+
+ revealNextSearchResult(changeFocus)
+ {
+ this._lastActiveEditor.revealNextSearchResult(changeFocus);
+ }
+
+ revealPosition(position, textRangeToSelect, forceUnformatted)
+ {
+ this._lastActiveEditor.revealPosition(position, textRangeToSelect, forceUnformatted);
+ }
+
+ // Private
+
+ _editorFocused(event)
+ {
+ if (this._lastActiveEditor === event.target)
+ return;
+
+ let currentSearchQuery = null;
+
+ if (this._lastActiveEditor) {
+ currentSearchQuery = this._lastActiveEditor.currentSearchQuery;
+
+ this._lastActiveEditor.searchCleared();
+ }
+
+ this._lastActiveEditor = event.target;
+
+ if (currentSearchQuery)
+ this._lastActiveEditor.performSearch(currentSearchQuery);
+ }
+
+ _numberOfSearchResultsDidChange(event)
+ {
+ this.dispatchEventToListeners(WI.ContentView.Event.NumberOfSearchResultsDidChange);
+ }
+};
--- /dev/null
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WI.ShaderProgramTreeElement = class ShaderProgramTreeElement extends WI.GeneralTreeElement
+{
+ constructor(shaderProgram)
+ {
+ console.assert(shaderProgram instanceof WI.ShaderProgram);
+
+ const subtitle = null;
+ super("shader-program", shaderProgram.displayName, subtitle, shaderProgram);
+ }
+};
this._codeMirror.setOption("showWhitespaceCharacters", WI.settings.showWhitespaceCharacters.value);
});
+ this._codeMirror.on("focus", this._editorFocused.bind(this));
this._codeMirror.on("change", this._contentChanged.bind(this));
this._codeMirror.on("gutterClick", this._gutterMouseDown.bind(this));
this._codeMirror.on("gutterContextMenu", this._gutterContextMenu.bind(this));
return !this._codeMirror.isClean();
}
+ _editorFocused(codeMirror)
+ {
+ this.dispatchEventToListeners(WI.TextEditor.Event.Focused);
+ }
+
_contentChanged(codeMirror, change)
{
if (this._ignoreCodeMirrorContentDidChangeEvent > 0)
WI.TextEditor.HighlightAnimationDuration = 2000;
WI.TextEditor.Event = {
+ Focused: "text-editor-focused",
ExecutionLineNumberDidChange: "text-editor-execution-line-number-did-change",
NumberOfSearchResultsDidChange: "text-editor-number-of-search-results-did-change",
ContentDidChange: "text-editor-content-did-change",
<None Include="..\UserInterface\EventListenerSectionGroup.js" />
<None Include="..\UserInterface\ExecutionContext.js" />
<None Include="..\UserInterface\ExecutionContextList.js" />
+ <None Include="..\UserInterface\External\CodeMirror\clike.js" />
<None Include="..\UserInterface\External\CodeMirror\clojure.js" />
<None Include="..\UserInterface\External\CodeMirror\closebrackets.js" />
<None Include="..\UserInterface\External\CodeMirror\codemirror.css" />
<None Include="..\UserInterface\WebInspector.js">
<Filter>UserInterface</Filter>
</None>
+ <None Include="..\UserInterface\External\CodeMirror\clike.js">
+ <Filter>UserInterface\External\CodeMirror</Filter>
+ </None>
<None Include="..\UserInterface\External\CodeMirror\clojure.js">
<Filter>UserInterface\External\CodeMirror</Filter>
</None>