Hello Emacs Enthusiasts

Emacs enthusiasts can be terribly busy setting up an emacs dev environment. Emacs isn't an all in one off the shelf piece of software. It's a world unto its own. A fully complete, educational experience.

Emacs enthusiasts, you are not forgotten. Others who walk the same path are here to help you along your way, for better or for worse (hopefully for better).

Here at Reading World Magazine, behind the scenes, emacs enthusiasts are appreciated. We're here to help.

Today we’re helping you out with Company-Mode - Yasnippet integration

Here's the problem:

You started out with emacs and finally figured out how to get an auto-completion framework installed.

Let's say you chose company-mode over auto-complete (a good decision).

And you've already found Yasnippet...(well done).

So what now? Do you make a file for every snippet in your yasnippet directory, and fill it out?

That couldn't be the emacs solution? Other editors come with snippets systems pre-installed.

Well, there is another way.

Get Atom snippets, in json or coffee script, and parse them into your yasnippet repository.

When I first did this, I used a web server to parse json snippets to a web page, then manually copied them into an emacs org-mode file and customized an existing emacs function to parse that org-mode file into snippets.

Now I have snippets, but were I to do the same thing today, I'd use node and output the results to an org-mode file directly. I'd also use org-mode's included source block exporter.

I'll show you the first way, but let me know if you want to see the node solution.

Step 1: Let’s find some snippets

1. Here are some emmet snippets directories.

https://github.com/emmetio/emmet/blob/master/snippets/css.json

https://github.com/emmetio/emmet/blob/master/snippets/html.json

2. There are snippets all over the internet. For this method, use .json files.

3. Atom snippets come in .cson, coffee script format, so you can find those on github and convert them to json easily.

4. Note: you will want to edit your snippets to get them just right 😏 - pay close attention to yasnippet formats.

Step 2: Let’s produce some snippets

Structure the json file to follow this structure:



{
"html": {
    "anchor-icon": {
    "prefix": "anchor-icon",
    "body": "<a class = \"${1:class}\" href=\"${2:path/file.html}\" target=\"${3:_blank|_self|_parent|_top|framename}\"> \n${4:LINK TEXT}\n<img src=\"${5:path/newtab.svg}\" alt=\"${6:(opens in new tab)}\">\n</a>",
    "description": "HTML - hyperlink with image inside",
    "scope": "text.html"
    },
    "anchor-simple": {
    "prefix": "anchor-simple",
    "body": "<a class = \"${1:class}\" href=\"${2:path/file.html}\" target=\"${3:_blank|_self|_parent|_top|framename}\">${4:LINK TEXT}</a>",
    "description": "HTML - hyperlink skip 
    (jumps to matching # element, position: absolute;top:-3em;)",
    "scope": "text.html"
    }
}
}

1. Increase snippet keys until sufficient.

2. Prefix equals key (what will be typed to produce snippet)

3. Key also will equal org-mode heading for each snippet

4. Body will equal snippet

5. Description will equal name (in yasnippet format)

6. Use online libraries to finalize snippets:

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/em

https://www.tutorialrepublic.com/html-reference/html5-tags.php

Step 3: Write javascript and html files to convert snippets to html

Note: node users, use node, skip the webserver, and write to file using fs module.

More Notes:

1. use fetch, .GET_JSON (ajax), or convert json file to json object and use modules to import

2. parse the json object

3. use the keys Object.keys(html) to loop through the object with keys.forEach(key, index)

4. print data to yasnippet format within html (I used xmp tag, but you could use a pre tag.)

Here's the script:


"use strict";

//set variables at this scope (public here) for objects
let html = {};

let finalResult = new Array;

finalResult = "<div>";

// convert object to key's array
let loadResult =  function(){

const keys = Object.keys(html);

// iterate over object
keys.forEach((key, index) => { 
let result = '* ' + key + '</br># name: ' + html[key]['description'] + '</br>' + '# key: ' + key  + '</br>' + '# --' + '</br>' +'<xmp>' + html[key]['body'] + '</xmp></br></br>';
finalResult += result;
});

finalResult += "</div>";
//console.log(finalResult);
}//end loadResult

fetch("./htmlSnippets.json")
.then(function(resp){
return resp.json();
})

.then(function(data){

html = data.html;
loadResult();

$('#output').html(finalResult);
});

Note:

That script is from two years ago. It requires jQuery, which you probably do not want to use. Use:


let your_element_variable = document.getElementById('output');

your_element_variable.insertAdjacentHTML('beforeend', finalResult);

Also, if you write the script with emacs src blocks, you can use org-modes included export structure.

Here’s the html


<!DOCTYPE html>
<html lang = "en-US">

<head>
<meta charset = "UTF-8">
<title>Printing JSON Snippets To HTML</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

<script type="text/javascript" src= "parse-json-html-to-html-snippets.js"></script>

<style>
body {
-webkit-font-smoothing: antialiased;
background-color:#f1f1f1;
color:black;
}
div > p {
margin: -5px 0px -5px 0px;
}
</style>
</head>
<body>


<div id = "output">
</div>


</body>
</html>

Note: remove the jquery line.

Node users, there is a better way to do this. Use node.

Step 4: Serve the html and javascript from a local server

1. easy just start your server and go to the file

Step 5: Copy the served html to an org file

1. you want these lines in the meta data (you don't need the title):


#+TITLE: HTML SNIPPETS PARSED FROM JSON
#+OPTIONS: toc:nil title:nil

Step 6: Parse the org file and print each section to a snippet file

1. If you included org-mode src blocks in your output, use org-babel tangle

2. Last year I customized a function for this (using code from a few functions I found on the net)

Here it is:



(defun export-yasnippets-from-org (&optional name)
  "Cut the subtree currently being edited and create a new file from it.
If called with the universal argument, prompt for new filename, 
otherwise use the subtree title."
  (interactive "P")
  (org-with-wide-buffer
   (save-mark-and-excursion
     ;; Loop through each headline.
     (org-map-entries
      (lambda ()
      (let ((filename (cond
                   (current-prefix-arg
                    (expand-file-name
                     (read-file-name "New file name: ")))
                   (t
                    (concat
                     (expand-file-name
                      (org-element-property :title
                                            (org-element-at-point))
                      default-directory)
                     "")))))
          ;; Set the active region.
            (forward-line 1)
            (set-mark (point))
            (outline-next-preface)
           (easy-kill)
          (find-file-noselect filename)
    (with-temp-file filename
      (org-mode)
      (yank))))))));end export yasnipets from org

There you go, that's one way to parse json or cson files into yasnippets.

You will need to customize company-mode to work with yasnippet, but that's another story.

See you next time…