Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emmet: Encode\Decode action & preferences #9002

Closed
wants to merge 19 commits into from
Closed

Emmet: Encode\Decode action & preferences #9002

wants to merge 19 commits into from

Conversation

mrmlnc
Copy link
Contributor

@mrmlnc mrmlnc commented Jul 9, 2016

As I promised before, here’s a detailed description of what’s happening in the code.

Description

I contacted with the developer of Emmet (@sergeche) and made a bit of changes for creating an ability of using asynchronous API, and handle any errors, such as file does not exist, reading errors, write errors etc.

This PR close following issues and PR: #8569, #8324, #8586, #8542, which were created before.

Changelog

There’s a main changes that this PR make:

  1. Update Emmet to 1.6.0 version. Changelog for Emmet in addition to the asynchronous API:
    1. Added a meta tag for Edge commit
    2. Resolved #428 commit
    3. Fixed annoying issue with locating CSS rule commit
    4. Added code snippets for SVG commit
    5. Added meta:redirect snippet commit
    6. Added more boolean attributes for profile.booleanAttributes commit
    7. Switched to extenal Can I Use database commit
  2. Support of SVG, based on open file extension is added. (see 1.4).
  3. The process of set/reset settings and snippets for Emmet has been simplify. We don’t have to support undocumented features of Emmet, which don’t have any sense for the end user.
  4. The checking for the case when user specify the path, which open out of the current directory.
  5. Added function buffer in the file src/vs/base/node/request.ts, since the function text returns a string. This function returns the buffer.
  6. Added layer between Emmet and methods Editor for work with the file system (FileAccessor).
  7. FileAccessor is enabled only for actions Encode\Decode and Update Image Size.
  8. The emulator of prompt function, which used in file base64 for transmit path to the Emmet, has been delete (it is not necessary in version 1.6.0).
  9. The action Encode\Decode is again enabled.

Why the base64 has a lot of code?

For user comfortable it’s necessary to process several situations:

  1. Decoding a data:URL image is only available inside a workspace folder.
  2. Checking the validity of path:
    1. The path must be inside of open directory.
    2. The filename must consist valid symbols.
  3. If the file with specified name is already exist, it’s necessary to provide the user a choice (overwrite)

Automated tests

I try to create automatic tests for this command, but got an editor error. The log is below. The source code for the test: Gist.

Despite of error, console.log in the test (inside the test file) file displays the correct result. I can’t find a reason of this.

Error log: Cannot read property 'getStartPosition' of null

    WARNING: Promise with no error callback:58
  { exception:
    TypeError: Cannot read property 'getStartPosition' of null
        at EditorAccessor.getSyntax (C:\projects\vscode-master\out\vs\workbench\parts\emmet\node\editorAccessor.js:93:54)
        at Object.outputInfo (C:\projects\vscode-master\node_modules\emmet\lib\utils\editor.js:57:37)
        at Object.expandAbbreviationAction (C:\projects\vscode-master\node_modules\emmet\lib\action\expandAbbreviation.js:106:27)
        at Object.run (C:\projects\vscode-master\node_modules\emmet\lib\action\main.js:150:21)
        at Object.run (C:\projects\vscode-master\node_modules\emmet\lib\emmet.js:81:23)
        at ExpandAbbreviationAction.BasicEmmetEditorAction.runEmmetAction (C:\projects\vscode-master\out\vs\workbench\parts\emmet\node\emmetActions.js:82:25)
        at C:\projects\vscode-master\out\vs\workbench\parts\emmet\node\emmetActions.js:51:27
        at ExpandAbbreviationAction.EmmetEditorAction._withEmmetPreferences (C:\projects\vscode-master\out\vs\workbench\parts\emmet\node\emmetActions.js:65:17)
        at C:\projects\vscode-master\out\vs\workbench\parts\emmet\node\emmetActions.js:49:23
        at Object.notifySuccess [as _notify] (C:\projects\vscode-master\out\vs\base\common\winjs.base.raw.js:1170:59)
        at Object.state_success_notify.enter (C:\projects\vscode-master\out\vs\base\common\winjs.base.raw.js:852:30)
        at Promise_ctor._Base.Class.define._run (C:\projects\vscode-master\out\vs\base\common\winjs.base.raw.js:1068:29)
        at Promise_ctor._Base.Class.define._completed (C:\projects\vscode-master\out\vs\base\common\winjs.base.raw.js:1036:18)
        at Module._invokeFactory (C:\projects\vscode-master\out\vs\loader.js:755:52)
        at Module._complete (C:\projects\vscode-master\out\vs\loader.js:776:34)
        at Module.resolveDependency (C:\projects\vscode-master\out\vs\loader.js:831:22)
        at ModuleManager._onModuleComplete (C:\projects\vscode-master\out\vs\loader.js:1190:39)
        at ModuleManager._resolve (C:\projects\vscode-master\out\vs\loader.js:1525:22)
        at ModuleManager.defineModule (C:\projects\vscode-master\out\vs\loader.js:1027:18)
        at ModuleManager._onLoad (C:\projects\vscode-master\out\vs\loader.js:1113:34)
        at Object.callback (C:\projects\vscode-master\out\vs\loader.js:1488:31)
        at OnlyOnceScriptLoader.triggerCallback (C:\projects\vscode-master\out\vs\loader.js:1559:36)
        at C:\projects\vscode-master\out\vs\loader.js:1553:80
        at NodeScriptLoader.load (C:\projects\vscode-master\out\vs\loader.js:1727:17)
        at OnlyOnceScriptLoader.load (C:\projects\vscode-master\out\vs\loader.js:1553:37)
        at loadNextPath (C:\projects\vscode-master\out\vs\loader.js:1483:41)
        at Object.errorback (C:\projects\vscode-master\out\vs\loader.js:1491:25)
        at OnlyOnceScriptLoader.triggerErrorback (C:\projects\vscode-master\out\vs\loader.js:1566:36)
        at C:\projects\vscode-master\out\vs\loader.js:1553:141
        at ReadFileContext.callback (C:\projects\vscode-master\out\vs\loader.js:1733:25)
        at FSReqWrap.readFileAfterOpen [as oncomplete] (fs.js:359:13),
    error: null,
    promise:
    { _creator: null,
      _nextState: null,
      _state:
        { name: 'error',
          enter: [Function],
          cancel: [Function: _],
          done: null,
          then: null,
          _completed: [Function: _],
          _error: [Function: _],
          _notify: [Function: notifyError],
          _progress: [Function: _],
          _setCompleteValue: [Function: _],
          _setErrorValue: [Function: _] },
      _value:
        TypeError: Cannot read property 'getStartPosition' of null
            at EditorAccessor.getSyntax (C:\projects\vscode-master\out\vs\workbench\parts\emmet\node\editorAccessor.js:93:54)
            at Object.outputInfo (C:\projects\vscode-master\node_modules\emmet\lib\utils\editor.js:57:37)
            at Object.expandAbbreviationAction (C:\projects\vscode-master\node_modules\emmet\lib\action\expandAbbreviation.js:106:27)
            at Object.run (C:\projects\vscode-master\node_modules\emmet\lib\action\main.js:150:21)
            at Object.run (C:\projects\vscode-master\node_modules\emmet\lib\emmet.js:81:23)
            at ExpandAbbreviationAction.BasicEmmetEditorAction.runEmmetAction (C:\projects\vscode-master\out\vs\workbench\parts\emmet\node\emmetActions.js:82:25)
            at C:\projects\vscode-master\out\vs\workbench\parts\emmet\node\emmetActions.js:51:27
            at ExpandAbbreviationAction.EmmetEditorAction._withEmmetPreferences (C:\projects\vscode-master\out\vs\workbench\parts\emmet\node\emmetActions.js:65:17)
            at C:\projects\vscode-master\out\vs\workbench\parts\emmet\node\emmetActions.js:49:23
            at Object.notifySuccess [as _notify] (C:\projects\vscode-master\out\vs\base\common\winjs.base.raw.js:1170:59)
            at Object.state_success_notify.enter (C:\projects\vscode-master\out\vs\base\common\winjs.base.raw.js:852:30)
            at Promise_ctor._Base.Class.define._run (C:\projects\vscode-master\out\vs\base\common\winjs.base.raw.js:1068:29)
            at Promise_ctor._Base.Class.define._completed (C:\projects\vscode-master\out\vs\base\common\winjs.base.raw.js:1036:18)
            at Module._invokeFactory (C:\projects\vscode-master\out\vs\loader.js:755:52)
            at Module._complete (C:\projects\vscode-master\out\vs\loader.js:776:34)
            at Module.resolveDependency (C:\projects\vscode-master\out\vs\loader.js:831:22)
            at ModuleManager._onModuleComplete (C:\projects\vscode-master\out\vs\loader.js:1190:39)
            at ModuleManager._resolve (C:\projects\vscode-master\out\vs\loader.js:1525:22)
            at ModuleManager.defineModule (C:\projects\vscode-master\out\vs\loader.js:1027:18)
            at ModuleManager._onLoad (C:\projects\vscode-master\out\vs\loader.js:1113:34)
            at Object.callback (C:\projects\vscode-master\out\vs\loader.js:1488:31)
            at OnlyOnceScriptLoader.triggerCallback (C:\projects\vscode-master\out\vs\loader.js:1559:36)
            at C:\projects\vscode-master\out\vs\loader.js:1553:80
            at NodeScriptLoader.load (C:\projects\vscode-master\out\vs\loader.js:1727:17)
            at OnlyOnceScriptLoader.load (C:\projects\vscode-master\out\vs\loader.js:1553:37)
            at loadNextPath (C:\projects\vscode-master\out\vs\loader.js:1483:41)
            at Object.errorback (C:\projects\vscode-master\out\vs\loader.js:1491:25)
            at OnlyOnceScriptLoader.triggerErrorback (C:\projects\vscode-master\out\vs\loader.js:1566:36)
            at C:\projects\vscode-master\out\vs\loader.js:1553:141
            at ReadFileContext.callback (C:\projects\vscode-master\out\vs\loader.js:1733:25)
            at FSReqWrap.readFileAfterOpen [as oncomplete] (fs.js:359:13),
      _isException: true,
      _errorId: 58,
      done: [Function: ErrorPromise_done],
      then: [Function: ErrorPromise_then] },
    handler: undefined,
    id: 58,
    parent: undefined }
  TypeError: Cannot read property 'getStartPosition' of null
      at EditorAccessor.getSyntax (C:\projects\vscode-master\out\vs\workbench\parts\emmet\node\editorAccessor.js:93:54)
      at Object.outputInfo (C:\projects\vscode-master\node_modules\emmet\lib\utils\editor.js:57:37)
      at Object.expandAbbreviationAction (C:\projects\vscode-master\node_modules\emmet\lib\action\expandAbbreviation.js:106:27)
      at Object.run (C:\projects\vscode-master\node_modules\emmet\lib\action\main.js:150:21)
      at Object.run (C:\projects\vscode-master\node_modules\emmet\lib\emmet.js:81:23)
      at ExpandAbbreviationAction.BasicEmmetEditorAction.runEmmetAction (C:\projects\vscode-master\out\vs\workbench\parts\emmet\node\emmetActions.js:82:25)
      at C:\projects\vscode-master\out\vs\workbench\parts\emmet\node\emmetActions.js:51:27
      at ExpandAbbreviationAction.EmmetEditorAction._withEmmetPreferences (C:\projects\vscode-master\out\vs\workbench\parts\emmet\node\emmetActions.js:65:17)
      at C:\projects\vscode-master\out\vs\workbench\parts\emmet\node\emmetActions.js:49:23
      at Object.notifySuccess [as _notify] (C:\projects\vscode-master\out\vs\base\common\winjs.base.raw.js:1170:59)
      at Object.state_success_notify.enter (C:\projects\vscode-master\out\vs\base\common\winjs.base.raw.js:852:30)
      at Promise_ctor._Base.Class.define._run (C:\projects\vscode-master\out\vs\base\common\winjs.base.raw.js:1068:29)
      at Promise_ctor._Base.Class.define._completed (C:\projects\vscode-master\out\vs\base\common\winjs.base.raw.js:1036:18)
      at Module._invokeFactory (C:\projects\vscode-master\out\vs\loader.js:755:52)
      at Module._complete (C:\projects\vscode-master\out\vs\loader.js:776:34)
      at Module.resolveDependency (C:\projects\vscode-master\out\vs\loader.js:831:22)
      at ModuleManager._onModuleComplete (C:\projects\vscode-master\out\vs\loader.js:1190:39)
      at ModuleManager._resolve (C:\projects\vscode-master\out\vs\loader.js:1525:22)
      at ModuleManager.defineModule (C:\projects\vscode-master\out\vs\loader.js:1027:18)
      at ModuleManager._onLoad (C:\projects\vscode-master\out\vs\loader.js:1113:34)
      at Object.callback (C:\projects\vscode-master\out\vs\loader.js:1488:31)
      at OnlyOnceScriptLoader.triggerCallback (C:\projects\vscode-master\out\vs\loader.js:1559:36)
      at C:\projects\vscode-master\out\vs\loader.js:1553:80
      at NodeScriptLoader.load (C:\projects\vscode-master\out\vs\loader.js:1727:17)
      at OnlyOnceScriptLoader.load (C:\projects\vscode-master\out\vs\loader.js:1553:37)
      at loadNextPath (C:\projects\vscode-master\out\vs\loader.js:1483:41)
      at Object.errorback (C:\projects\vscode-master\out\vs\loader.js:1491:25)
      at OnlyOnceScriptLoader.triggerErrorback (C:\projects\vscode-master\out\vs\loader.js:1566:36)
      at C:\projects\vscode-master\out\vs\loader.js:1553:141
      at ReadFileContext.callback (C:\projects\vscode-master\out\vs\loader.js:1733:25)
      at FSReqWrap.readFileAfterOpen [as oncomplete] (fs.js:359:13)
  ....................
  Cannot read property 'getStartPosition' of null
  Error: oops
      at ErrorHandler.unexpectedErrorHandler (C:\projects\vscode-master\test\all.js:184:12)
      at ErrorHandler.onUnexpectedError (C:\projects\vscode-master\out\vs\base\common\errors.js:42:18)
      at Object.onUnexpectedError (C:\projects\vscode-master\out\vs\base\common\errors.js:56:34)
      at C:\projects\vscode-master\out\vs\base\common\winjs.base.js:41:18
      at Array.forEach (native)
      at Timeout._onTimeout (C:\projects\vscode-master\out\vs\base\common\winjs.base.js:38:25)
      at tryOnTimeout (timers.js:224:11)
      at Timer.listOnTimeout (timers.js:198:5)
  .

    1803 passing (18s)
    2 failing

    1) Basic Emmet actions expandAbbreviationTest:
      Error: timeout of 10000ms exceeded. Ensure the done() callback is being called in this test.
        at Timeout.<anonymous> (C:\projects\vscode-master\node_modules\mocha\lib\runnable.js:226:19)

    2) Errors should not have unexpected errors in tests:

        AssertionError: false == true
        + expected - actual

        -false
        +true

        at Context.<anonymous> (C:\projects\vscode-master\test\all.js:175:13)
        at callFn (C:\projects\vscode-master\node_modules\mocha\lib\runnable.js:326:21)
        at Test.Runnable.run (C:\projects\vscode-master\node_modules\mocha\lib\runnable.js:319:7)
        at Runner.runTest (C:\projects\vscode-master\node_modules\mocha\lib\runner.js:422:10)
        at C:\projects\vscode-master\node_modules\mocha\lib\runner.js:528:12
        at next (C:\projects\vscode-master\node_modules\mocha\lib\runner.js:342:14)
        at C:\projects\vscode-master\node_modules\mocha\lib\runner.js:352:7
        at next (C:\projects\vscode-master\node_modules\mocha\lib\runner.js:284:14)
        at Immediate._onImmediate (C:\projects\vscode-master\node_modules\mocha\lib\runner.js:320:5)



  npm ERR! Test failed.  See above for more details.

I also wrote the basic tests for FileAccessor, but i didn’t include them in this PR. They are available in Gist.

This tests are useful after little changes of a class FileAccessor:

  1. In the locateFile method should return this.fileService.existsFile.
  2. In the read method should return buffer и this.fileService.resolveContent.
  3. In the save method should return this.fileService.updateContent.

Because of automatic tests don’t work, I wrote the instructions for manual testing.

Manual tests

  1. Check for encoding and decoding for files from network and disks.

  • Open the directory and create a CSS file.

  • Insert the following code into the newly created file:

    .test {
        background-image: url(https://avatars3.githubusercontent.com/u/7034281?v=3&s=40);
    }
  • Run Encode\Decode command. The correct result: background-image: url(data:application/octet-stream;base64,/9j/2wCEAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSE…);

  • Run Encode/Decode command in the same file.

  • Write the name test.png. File must be saved, and property looks following: background-image: url (test.png);.

  • Rerun Encode\Decode command. The correct result: as in item 3 above.

    1. Check of processing cancellation of decode and display a simple errors.

  • Repeat the first three steps described above (1.1 - 1.3).

  • Run Encode\Decode command and press Escape key. Nothing's going to happen.

  • Run Encode\Decode and write the following text: ../../test.png. You should see:

    image

  • Run Encode\Decode and write the following text: test:::image.png. You should see:

    image

    1. Checking display of warnings.

  • Repeat the first six steps described above (1.1 - 1.5).

  • Change image url on https://avatars2.githubusercontent.com/u/172399?v=3&s=60.

  • Run Encode\Decode action and write test.png. You should see:

    image

  • Agree to overwrite.

  • Open the file test.png. You should see avatar @egamma.

    1. Checking display warnings about missing files.

  • Open the directory and create a CSS file.

  • Insert the following code into the newly created file:

    .test {
        background-image: url(https://www.canonium.com/fileNotExist.svg);
    }
  • Run Encode\Decode action. You should see:

    image

  • Replace the path in background-image property to a new value: fileNotExist.png.

  • Run Encode\Decode action. You should see:

    image

  • @mention-bot
    Copy link

    @mrmlnc, thanks for your PR! By analyzing the annotation information on this pull request, we identified @egamma and @alexandrudima to be potential reviewers

    @mrmlnc mrmlnc changed the title Emmet: Encode\Decode command & Emmet preferences Emmet: Encode\Decode action & preferences Jul 9, 2016
    @egamma
    Copy link
    Member

    egamma commented Jul 25, 2016

    @mrmlnc I'm sorry but I didn't get to this PR before my vacation and it is getting tight for the July iteration. One issue is that emmet 1.6 adds a new dependency to caniuse-db, that we need to track.

    @egamma
    Copy link
    Member

    egamma commented Jul 25, 2016

    @mrmlnc there is some significant size increase between emmet 1.3.1 and emmet 1.6 and this needs a justification:

    • emmet 1.3 -> 2.3MB, 130 files
    • emmet 1.6 -> 9MB, 747 files

    While the emmet 1.6 module itself got smaller and is now 1.8 MB, the caniuse-db module adds 7 MB.

    So how can the size difference be justified?

    @mrmlnc
    Copy link
    Contributor Author

    mrmlnc commented Jul 25, 2016

    Hello, @egamma, you are well rested? 🎿 ☀️

    Nice catch. Unfortunately, i have not checked this case. The module CanIuse contains a lot of unnecessary information for us.

    The way out of this situation will be building Emmet by Gulp. Theoretically this can solve some issues such as #4076. If you remember, I conducted the tests, but it was on a fast SSD drive.

    P.S.: The author plans to completely rewrite Emmet, so we can postpone this matter at any time convenient for you. I don't think a lot of people use this feature Emmet.

    @egamma
    Copy link
    Member

    egamma commented Jul 26, 2016

    @mrmlnc

    The way out of this situation will be building Emmet by Gulp.

    The way we currently build VS Code is that we npm install the dependencies. The build currently doesn't support post install steps for dependencies. My preference would be an emmet-built npm module that we can consume directly. This module should not be VS Code specific and the Atom, Sublime and other Emmet integrations would also benefit from such an optimized module.

    One thing we are also considering is to move emmet into an extension.

    I don't think a lot of people use this feature Emmet.

    Then let's defer it for now. This is still a great PR, thank you 🌹

    @mrmlnc
    Copy link
    Contributor Author

    mrmlnc commented Jul 26, 2016

    @egamma,

    My preference would be an emmet-built npm module that we can consume directly.

    I will discuss this issue with the creator of Emmet.

    One thing we are also considering is to move emmet into an extension.

    Great idea.

    @egamma
    Copy link
    Member

    egamma commented Oct 6, 2016

    @mrmlnc I'm closing this PR for now.

    @Fred-Vatin
    Copy link

    Hi,

    I can not find the Encode/Decode Image to data:URL command in the palette and in the emmet commands list.

    What about you guys ? Is it missing for everyone?

    • VS Code v1.10.2 with default setup
    • Win 10 pro x64 french

    @ramya-rao-a
    Copy link
    Contributor

    @freMea No this hasn't been implemented in VS Code yet.

    You can follow #27978 for updates on this feature

    @github-actions github-actions bot locked and limited conversation to collaborators Mar 27, 2020
    Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
    Labels
    None yet
    Projects
    None yet
    Development

    Successfully merging this pull request may close these issues.

    BEM: Block inside another block?
    6 participants