function _insertFontCompletionAtCursor(completion, editor, cursor) { var token; var actualCompletion = completion; var stringChar = "\""; if (_documentIsCSS(editor.document)) { // on the off-chance we changed documents, don't change anything token = parser.getFontTokenAtCursor(editor, cursor); if (token) { // get the correct string character if there is already one in use if (token.className === "string") { stringChar = token.string.substring(0, 1); } // wrap the completion in string character if either // a.) we're inserting into a string, or // b.) the slug contains a space if (token.className === "string" || whitespaceRegExp.test(actualCompletion)) { actualCompletion = stringChar + actualCompletion + stringChar; } // Check if we're modifying an existing string. If so, it's possible that we're // in a situation with only one quote (i.e. the parser thinks the rest of the // line is a string. So, we want to stop at the first occurrence of a comma or // semi-colon. var endChar = token.end; if (token.className === "string") { // Find the *first* comma or semi var match = commaSemiRegExp.exec(token.string); if (match) { endChar = token.start + match.index; } } // HACK (tracking adobe/brackets#1688): We talk to the private CodeMirror instance // directly to replace the range instead of using the Document, as we should. The // reason is due to a flaw in our current document synchronization architecture when // inline editors are open. if (token.className === "string" || token.className === "variable-2" || token.className === "string-2") { // replace editor._codeMirror.replaceRange(actualCompletion, {line: cursor.line, ch: token.start}, {line: cursor.line, ch: endChar}); } else { // insert editor._codeMirror.replaceRange(actualCompletion, cursor); } } } // record it in our font history var i = lastTwentyFonts.indexOf(completion); if (i >= 0) { lastTwentyFonts.splice(i, 1); } lastTwentyFonts.splice(0, 0, completion); // add completion to front of array if (lastTwentyFonts.length > 20) { lastTwentyFonts.splice(20, lastTwentyFonts.length - 20); } prefs.setValue(PREFERENCES_FONT_HISTORY_KEY, lastTwentyFonts); }
FontHints.prototype.hasHints = function (editor, implicitChar) { this.editor = editor; if (_documentIsCSS(editor.document)) { if (!implicitChar) { if (parser.getFontTokenAtCursor(editor, editor.getCursorPos())) { return true; } } else if (fontnameStartRegExp.test(implicitChar)) { // We only display the hint list implicitly if the following conditions are both met: // 1. The implicit char is a word character or a quote (covered by the test above) // 2. We're in a font-family rule (covered by checking parser.getFontTokenAtCursor !== null) // We check them in this order because checking the implict char is much cheaper. var currentPosition = editor.getCursorPos(); if (currentPosition.ch >= 1) { var currentToken = parser.getFontTokenAtCursor(editor, editor.getCursorPos()); if (currentToken) { return true; } } } } return false; };
FontHints.prototype.getHints = function (key) { var editor = this.editor, cursor = editor.getCursorPos(), query, lowerCaseQuery, token; if (_documentIsCSS(editor.document)) { token = parser.getFontTokenAtCursor(editor, cursor); if (token) { if (token.className === "string") { // is wrapped in quotes if (token.start < cursor.ch) { // actually in the text query = token.string.substring(1, cursor.ch - token.start); if (token.end === cursor.ch) { // at the end, so need to clip off closing quote query = query.substring(0, query.length - 1); } } else { // not in the text query = ""; } } else if (token.className === "variable-2" || token.className === "string-2") { // is not wrapped in quotes query = token.string.substring(0, cursor.ch - token.start); } else { // after a ":", a space, or a "," query = ""; } // candidate hints are lower case, so the query should be too lowerCaseQuery = query.toLocaleLowerCase(); // we're going to handle this query, so we need to add our UI setTimeout(_augmentCodeHintUI, 1); var candidates = parser.parseCurrentEditor(true); candidates = candidates.concat(lastTwentyFonts); candidates = candidates.concat(webfont.getWebsafeFonts()); candidates = webfont.lowerSortUniqStringArray(candidates); candidates = webfont.filterAndSortArray(query, candidates); candidates = candidates.map(function (hint) { var index = hint.indexOf(lowerCaseQuery), $hintObj = $('<span>'), slugs = webfont.searchBySlug(hint); // load the matching font scripts individually for cachability slugs.forEach(function (slug) { var font = webfont.getFontBySlug(slug), script; if (!(scriptCache.hasOwnProperty(slug))) { script = webfont.createInclude([font]); $(script).appendTo("head"); scriptCache[slug] = true; } }); // emphasize the matching substring if (index >= 0) { $hintObj.append(hint.slice(0, index)) .append($('<span>') .append(hint.slice(index, index + query.length)) .css('font-weight', 'bold')) .append(hint.slice(index + query.length)); } else { $hintObj.text(hint); } // set the font family and attach the hint string as data $hintObj .append($('<span>') .append(Strings.SAMPLE_TEXT) .css('padding-right', '10px') .css('float', 'right') .css('font-family', hint + ", AdobeBlank")) .data('hint', hint); return $hintObj; }); return { hints: candidates, match: null, selectInitial: true }; } } return null; };