What it is:
I've worked the kinks out of an implementation of something similar to the suggestion above, which you can test out here (doesn't seem to be working in Chrome, for some reason). It differs in that there is no separate button: once you create a code block, a dropdown appears, giving you the option to add a language hint tag.
The code inside is still pretty horrible, (eg. using jQuery inside code with no jQuery dependency), but it can probably be refactored into something nicer with a little more work.
Screenshots:


How to use:
Adding hints:
- Select some text and use Ctrl+K or the
{}
button as normal
- A dropdown will appear above the newly indented code that you can use to select a language
- You can either select a language using the dropdown, or click anywhere else to ignore it
Note that any existing language hint tags within your selection will be removed. For example, consider the following markdown:
This is some sample text.
This part is non programming language data.
Select the second line and press Ctrl+K, then select "None" from the dropdown:
This is some sample text.
<!-- language: lang-none-->
This part is non programming language data.
If you were to now select the entirety of this and press Ctrl+K, then select "Default" in the dropdown, the output would be:
<!-- language: lang-default-->
This is some sample text.
This part is non programming language data.
Removing hints:
- Select some indented code, including the language hint tag at the beginning
- Use Ctrl+K or the
{}
button to dedent code into normal text
- The language hint is removed
Help please:
If anyone more familiar with the PageDown source can refactor the code, add more features, fix bugs etc., feel free to do so. I've set up a Github repo here.
The only thing I modified was the doCode
method of the CommandManager
prototype in Markdown.Editor.js
:
commandProto.doCode = function (chunk, postProcessing) {
//Test if there is text preceding the start of the selection on the first selected line
//or if there is text following the end of the selection on the last selected line
var hasTextBefore = /\S[ ]*$/.test(chunk.before);
var hasTextAfter = /^[ ]*\S/.test(chunk.after);
// Use 'four space' markdown if the selection is on its own
// line or is multiline.
if ((!hasTextAfter && !hasTextBefore) || /\n/.test(chunk.selection)) {
chunk.before = chunk.before.replace(/[ ]{4}$/,
function (totalMatch) {
chunk.selection = totalMatch + chunk.selection;
return "";
});
var nLinesBack = 1;
var nLinesForward = 1;
if (/(\n|^)(\t|[ ]{4,}).*\n$/.test(chunk.before)) {
nLinesBack = 0;
}
if (/^\n(\t|[ ]{4,})/.test(chunk.after)) {
nLinesForward = 0;
}
chunk.skipLines(nLinesBack, nLinesForward);
var langPos = chunk.before.length;
//Retrieve textarea and define dropdown creator
var txt = this.panels.input;
function dropdown(){
var pos,
langs = {
"None":"lang-none",
"Default":"lang-default",
"Bash":"lang-bsh",
"C":"lang-c",
"C++":"lang-cpp",
"C#":"lang-cs",
"CSH? I don't know":"lang-csh",
"CSS":"lang-css",
"Haskell":"lang-hs",
"HTML":"lang-html",
"Java":"lang-java",
"JavaScript":"lang-js",
"Lisp":"lang-lisp",
"Lua":"lang-lua",
"F#":"lang-ml",
"Perl":"lang-perl",
"PHP":"lang-php",
"Python":"lang-py",
"Proto":"lang-proto",
"Ruby":"lang-rb",
"Scala":"lang-scala",
"Shell":"lang-sh",
"SQL":"lang-sql",
"Visual Basic":"lang-vb",
"XML":"lang-xml"
};
//Use plugin to find coordinates of caret
$(txt).textareaHelper();
pos = $(txt).textareaHelper('caretPos');
$(txt).textareaHelper('destroy');
//Account for offset of textarea
pos.top += $(txt).offset().top
pos.left = $(txt).offset().left
console.log(pos);
//Populate dropdown with options
var langpicker = $('<select>');
langpicker.append(function(){
var option = $("<option>")
.prop({value:""})
.html("Select a language");
return option;
})
$.each(langs, function(i, v){
var option = $("<option>")
.prop({value:"<!-- language: " + v + "-->"})
.html(i);
langpicker.append(option);
});
//Position dropdown
langpicker.appendTo($('body')).css({
position: 'absolute',
left: pos.left + 2,
top: pos.top - langpicker.outerHeight(),
width: "200px"
})
.hide()
.fadeIn()
.focus()
.on('change blur', select);
//Callback function
function select(e){
var that = this;
if(e.type == "change"){
$(txt).val(function(i, v){
console.log(langPos, v.slice(langPos));
return v.slice(0, Math.max(langPos,0)) + $(that).val() + "\n\n" + v.slice(Math.max(langPos,0));
});
}
$(this).fadeOut(function(){
$(this).remove();
});
}
}
if (!chunk.selection) {
chunk.startTag = " ";
chunk.selection = this.getString("codeexample");
}
else {
//If the block isn't already code, add 4 spaces to the beginning of each line
if (/^(?![ ]*<\!-- language: lang-[a-z]+-->)[ ]{0,3}\S/m.test(chunk.selection)) {
if (/\n/.test(chunk.selection))
chunk.selection = chunk.selection.replace(/^[ ]{0,3}<\!-- language: lang-[a-z]+-->\n{0,2}/gm, "").replace(/^/gm, " ");
else // if it's not multiline, do not select the four added spaces; this is more consistent with the doList behavior
chunk.before += " ";
txt.setSelectionRange(langPos, langPos);
setTimeout(dropdown, 0);
}
//If the block already is code, remove spaces from the beginning of each line
else {
chunk.selection = chunk.selection.replace(/(?:(\n)?[ ]{4}|[ ]{0,3}\t)|(?:^<\!-- language: lang-[a-z]+-->\n*)/g, "$1");
}
}
}
else {
// Use backticks (`) to delimit the code block.
chunk.trimWhitespace();
chunk.findTags(/`/, /`/);
if (!chunk.startTag && !chunk.endTag) {
chunk.startTag = chunk.endTag = "`";
if (!chunk.selection) {
chunk.selection = this.getString("codeexample");
}
}
else if (chunk.endTag && !chunk.startTag) {
chunk.before += chunk.endTag;
chunk.endTag = "";
}
else {
chunk.startTag = chunk.endTag = "";
}
}
};
<!-- language: none -->
. Without it, random bits of data look really awful. All I can imagine is that folks don’t realize it exists.<!-- language: none -->
which would both solve the "random bits" problem and remind people of the feature.<!-- language: .... -->
, I actually had no idea that "none" was a valid option (if I had thought about it, I probably would have guessed it, but it didn't even occur to me). So I think your hypothesis is correct that folks just don't realize it exists.Net
- which results in C# highlighting of VB.Net code (works fine until you get to a code comment'
which is interpreted as a string start)