Pascal Emmet

I'll try to publish some code I use in my program.
User avatar
Rickard Johansson
Site Admin
Posts: 6736
Joined: 19 Jul 2006 14:29

Pascal Emmet

Post by Rickard Johansson »

In RJ TextEd I wrote my own version of Emmet. It is not based on the original Emmet code, but written from scratch in Delphi (object pascal).

You are perfectly free to use it in your own code or applications. But if you're using it in a commercial product I would appreciate a donation.

The Emmet code only expand abbreviation or wrap text with abbreviation. All other editor stuff like handle tab points or multi cursors you will have to handle yourself in your own code. That's what I do in RJ TextEd.

Cheat sheets
There are a few minor differences between my version of Emmet and standard Emmet (e.g. the lorem generator).

Emmet-Pascal cheat sheet: https://www.rj-texted.se/Help/topics/em ... tsheet.htm.
Standard Emmet cheat sheet: https://docs.emmet.io/cheat-sheet/

If you improve the code you may post it in this forum.

Version 1.18 (2020-06-30)
https://github.com/rickard67/Emmet-Pascal or https://github.com/Alexey-T/Emmet-Pascal


Changes:

Version 1.18
* Single quotes in custom attributes should work now. E.g. td[title='Hello world!' colspan=3]

Version 1.17
* Fixed a Lazarus (Free Pascal) string issue in ResolveTabStopsIndex()

Version 1.16 (2020-05-19)
* Added Delphi and Lazarus demos created by Alexey. Made some minor changes to the projects to build properly in the latest versions of Delphi 10.x and Lazarus. Otherwise no changes to the Emmet.pas code.

* If the result string contain both cursor positions and tab stops - cursor positions are replaced by tab stops.

Version 1.15
* Added option to replace cursor positions | with indexed tab positions ${x}

Version 1.14
* Fixed a typo in the snippets file and updated the zip file.

Version 1.14
* Fixed ${1:tabstop} index issue
* Fixed a class issue with span tag

Version 1.13
* Added support for markdown. Supported abbreviations are:

Code: Select all

      a           = link
      b           = bold
      bq          = blockquote
      code        = inline code snippet
      h1..h6      = heading
      hr          = horizontal rule
      i           = italic
      img         = image
      ol          = ordered list
      pre         = code block with language based highlighting
      strike      = strike through
      table       = table
      ul          = unordered list
      @l or @l80  = create lorem generated text
* Added a property to TEmmet to set a maximum multiplication limit. The default value is cMultiplicationMax = 1000.

Version 1.12
* Fixed a word wrap issue in Lorem generated text.

Version 1.11
* The option "CommentTags" in TExpandOptions didn't work. The |c filter did however.
* Added a number check in ProcessTagMultiplication() to prevent an infinite loop. (cMultiplicationMax = 1000)

Version 1.10
* Removed "public" keyword from TExpandOptions.
* Fixed an issue in ExtractFilters().

Version 1.09
* TEmmet can now handle some filters. A filter is added at the end of the abbreviation using a pipe |.

Code: Select all

      E.g. ul>li*|t

      c - Comment important tags (containing class or id attributes).
      e - Escape XML-unsafe characters: <, > and &. E.g. <p>|e => &lt;p&gt;&lt;/p&gt;
      s - Single line. Expand everything to a single line of code.
      t - Trim line markers from wrapped lines e.g. "* ", "- " or "1."
      w - Wordwrap selected or lorem generated text. Default width is 80.
      w<x> - Wordwrap at column x. E.g. |w120 will wrap lines at column 120.

      Ex.
        sAbbrev = ul>li*|t

        sSelText =
          * Line 1
          * Line 2

        Result =
          <ul>
            <li>Line 1</li>
            <li>Line 2</li>
          </ul>
* Added several options in a record "TExpandOptions" that can be passed to the expand function.
Options are:

Code: Select all

  AddSlashToEmptyTags: Boolean;  // Add a slash to empty tags e.g. <img src="" />
  AlwaysAddNewLine: Boolean;     // Always add linefeed after each tag (usually used in XML)
  CommentTags: Boolean;          // Comment important tags (containing class or id attributes).
  IndentChilds: Boolean;         // Indent child tags. If you set this to false - no indention will be used.
  SingleLine: Boolean            // Expand everything to a single line of code.
  TabSize: Integer;              // Tab size in characters. This is only used with wordwrap.
  TrimLineMarkers: Boolean;      // Trim line markers from wrapped lines e.g. "* ", "- " or "1."
  Wordwrap: Boolean;             // Word wrap selected or lorem generated text.
  WordwrapAt: Integer;           // Wrap at given column. The nearest space or symbol will be used as wrap position


* Added overload function to "ExpandAbbreviation()". The first one uses default options and the other one
enables you to set expand options.

Version 1.08
* Direction issue with multiply.
* Changes to the constructior.

Version 1.07
* Added support for placeholders $# used in "Wrap with abbreviation". The placeholder is replaced with one line of selected text.

Code: Select all

      E.g.
        sAbbrev = "ul>li[title=$#]*>{$#}+img[alt=$#]"

        sSelText =
           "About
            New
            Products
            Contacts"

        Result =
           "<ul>
              <li title="About">About<img src="" alt="About" /></li>
              <li title="New">New<img src="" alt="New" /></li>
              <li title="Products">Products<img src="" alt="Products" /></li>
              <li title="Contacts">Contacts<img src="" alt="Contacts" /></li>
           </ul>"
* Added new parameters to the constructor.

Version 1.06
* Space should be treated as stop character.
* Implicit tag issue.
* User attribute space issue.

Version 1.05
* Fixed a child indent issue.

Version 1.04
* Added standard vendor prefix "-" to CSS. E.g. -bdrs (which works the same as -v-bdrs).
* Space issue with siblings.
* A trim issue that may result in wrong indention.
* Id and class attribute issue.

Version 1.03
* Fixed several issues and updated the snippets.ini file.

Version 1.02
* Addressed some warnings in Lazarus

Version 1.01
* Fixed a multiply issue in ProcessTagMultiplication(...)
Alextp
Posts: 69
Joined: 23 Aug 2014 23:36

Re: Pascal Emmet

Post by Alextp »

Thank you very much! It is easier to get patches on Github, so I ve put repo here:
https://github.com/Alexey-T/Emmet-Pascal

Made fix to support FreePascal. (added var DirectorySeparator for Delphi, will test it ASAP.)
Alextp
Posts: 69
Joined: 23 Aug 2014 23:36

Re: Pascal Emmet

Post by Alextp »

In Lazarus it works, good. But the first abbrev from https://docs.emmet.io/abbreviations/
don't fully work.
#page>div.logo+ul#navigation>li*5>a{Item $}
Alextp
Posts: 69
Joined: 23 Aug 2014 23:36

Re: Pascal Emmet

Post by Alextp »

Added EmmetHelper unit (the same repo on github). It can find Emmet abbrev inside any line. It truncates line from <tag> and </tag> but skips Emmet ">" chars.
User avatar
Rickard Johansson
Site Admin
Posts: 6736
Joined: 19 Jul 2006 14:29

Re: Pascal Emmet

Post by Rickard Johansson »

Fixed the multiply issue in ProcessTagMultiplication(...) and added the new version in my first post.

Thanks!
Alextp
Posts: 69
Joined: 23 Aug 2014 23:36

Re: Pascal Emmet

Post by Alextp »

Thanks, that was fixed. I will test more cases, maybe all examples of Emmet, and will let you know. Will help as a tester.
Alextp
Posts: 69
Joined: 23 Aug 2014 23:36

Re: Pascal Emmet

Post by Alextp »

RIchard,
we need class (TEmmet) property: IndentString, which can be set to #9 or to StringOfChar(' ', N). You know it is needed for editors.
Alextp
Posts: 69
Joined: 23 Aug 2014 23:36

Re: Pascal Emmet

Post by Alextp »

And good to have property TabStopChar, with default value '|'.
User avatar
Rickard Johansson
Site Admin
Posts: 6736
Joined: 19 Jul 2006 14:29

Re: Pascal Emmet

Post by Rickard Johansson »

Indent
I do all the indent processing in the editor component. Using #9 as indent marker makes processing each line very simple and it's easy to replace with spaces. It's also easier to position the whole block where it's supposed to be.

Instead of adding that to the Emmet.pas - maybe you could write a helper function to process tabs. Maybe have an initial indent position "InitialIndentString" and "IndentString", or something similar...

| - tab stop char
The tab stop char is added to snippets and abbreviations in the file snippets.ini...
User avatar
Rickard Johansson
Site Admin
Posts: 6736
Joined: 19 Jul 2006 14:29

Re: Pascal Emmet

Post by Rickard Johansson »

Actually... It may be helpful to have an editor class (TEditor) that creates the TEmmet object and contain some helpful methods that makes it easier to use.
Alextp
Posts: 69
Joined: 23 Aug 2014 23:36

Re: Pascal Emmet

Post by Alextp »

Agree - IndentString is not needed, as well as prop for |.
I have founds bugs.
https://docs.emmet.io/cheat-sheet/

Bugs are
https://github.com/Alexey-T/Emmet-Pascal/issues
User avatar
Rickard Johansson
Site Admin
Posts: 6736
Joined: 19 Jul 2006 14:29

Re: Pascal Emmet

Post by Rickard Johansson »

They all work at my end :?

Are you using Lazarus? Could there be something in the code that works differently in Lazarus? Linefeeds maybe?

I use #13#10 as linefeed which works perfectly in Delphi and makes the result easy to process.
User avatar
Rickard Johansson
Site Admin
Posts: 6736
Joined: 19 Jul 2006 14:29

Re: Pascal Emmet

Post by Rickard Johansson »

Actually the abbreviation "c" isn't implemented (yet).
Alextp
Posts: 69
Joined: 23 Aug 2014 23:36

Re: Pascal Emmet

Post by Alextp »

Lazarus, yes. It gives warnings.
IMO these are the reason.

- main is "function ClimpUpOneLevel" result is not set. What result to set?
- func AddExpanded result is not inited. (you have Result:= Result+....)
- func GetAbbreviationNames: param AList must not be "out" - with "out" FreePascal uses write-only parameter
- func GetSnippetNames: AList must not be "out"
User avatar
Rickard Johansson
Site Admin
Posts: 6736
Joined: 19 Jul 2006 14:29

Re: Pascal Emmet

Post by Rickard Johansson »

Fixed (see first post). Hope that helps... :?
Post Reply