sunjw / jstoolnpp

A JavaScript (JSON) tool for Notepad++ (formerly JSMinNpp) and Visual Studio Code.
GNU General Public License v2.0
284 stars 24 forks source link

Compact mode #43

Closed supermerill closed 2 years ago

supermerill commented 7 years ago

Hi I made this "compact mode" for myself. I share it with you, in case you want to include it in your branch. I didn't test it with comments, arrays, nor exotics things. The two parameters doesn't have their gui yet (don't understand how to modify it, and didn't have the time to learn it).

Thank you for this awesome plugin! Merill

From b57b944a2c343b4497e5521251f2c8ddca314f78 Mon Sep 17 00:00:00 2001
From: merill <merill@free.fr>
Date: Wed, 15 Feb 2017 14:23:27 +0100
Subject: [PATCH] compact mode todo: bind the parameters into the gui

---
 trunk/src/jsparser.cpp        | 62 +++++++++++++++++++++++++++++++++---
 trunk/src/jsparser.h          |  4 ++-
 trunk/src/realjsformatter.cpp | 73 ++++++++++++++++++++++++++++++++++++++-----
 trunk/src/realjsformatter.h   |  9 ++++++
 4 files changed, 136 insertions(+), 12 deletions(-)

diff --git a/trunk/src/jsparser.cpp b/trunk/src/jsparser.cpp
index 24eb76d..c3682c4 100644
--- a/trunk/src/jsparser.cpp
+++ b/trunk/src/jsparser.cpp
@@ -393,12 +393,66 @@ bool JSParser::GetToken()
    {
        // 有排队的换行
        m_tokenB = m_tokenBQueue.front();
-       m_tokenBQueue.pop();
+       m_tokenBQueue.pop_front();
    }

    return (m_charA != 0 || m_tokenA.code != "");
 }

+int JSParser::HasAfter(char* code2Find, char* codeToAvoid, int maxTokens, int maxChars)
+{
+   TokenQueue temptokenBQueue = m_tokenBQueue;
+   TokenQueue alltokenBQueue;
+   Token m_tokenB_save = m_tokenB;
+   int findPos = -1;
+   int pos = 0;
+   int posChar = 0;
+   if (m_tokenB.code == code2Find && findPos<0) return 0;
+   if (m_tokenB.code == codeToAvoid && findPos<0) return 6666;
+   pos++;
+   posChar += m_tokenB.code.length();
+   //alltokenBQueue.push_back(m_tokenB);
+   for (int i = 0; i < m_tokenBQueue.size(); i++){
+       alltokenBQueue.push_back(m_tokenBQueue[i]);
+       if (alltokenBQueue[i].code == code2Find && findPos<0 && posChar<maxChars) findPos = pos;
+       if (alltokenBQueue[i].code == codeToAvoid && findPos<0) findPos = 7777;
+       pos++;
+       posChar += m_tokenBQueue[i].code.length();
+   }
+   while (alltokenBQueue.size() < maxTokens && findPos<0 && posChar<maxChars){
+       m_tokenBQueue = TokenQueue();
+       GetTokenRaw();
+       PrepareTokenB(); // 看看是不是要跳过换行
+       if (m_tokenB.code == code2Find && findPos<0) findPos = pos;
+       if (m_tokenB.code == codeToAvoid && findPos<0) findPos = 8888;
+       pos++;
+       posChar += m_tokenB.code.length();
+       alltokenBQueue.push_back(m_tokenB);
+       for (int i = 0; i < m_tokenBQueue.size(); i++){
+           alltokenBQueue.push_back(m_tokenBQueue[i]);
+           if (alltokenBQueue[i].code == code2Find && findPos<0 && posChar<maxChars) findPos = pos;
+           if (alltokenBQueue[i].code == codeToAvoid && findPos<0) findPos = 8888;
+           pos++;
+           posChar += m_tokenBQueue[i].code.length();
+       }
+   }
+
+   /*for (int i = 0; i < alltokenBQueue.size(); i++){
+       if (alltokenBQueue[i].code == "{"){
+           return i;
+       }
+   }*/
+
+   m_tokenBQueue = alltokenBQueue;
+   //m_tokenB = alltokenBQueue.front();
+   //alltokenBQueue.pop_front();
+   m_tokenB = m_tokenB_save;
+
+   if (findPos >= 0) return findPos;
+
+   return 9999;
+}
+
 void JSParser::PrepareRegular()
 {
    /*
@@ -486,12 +540,12 @@ void JSParser::PrepareTokenB()
        {
            temp.code = string("\n");
            temp.type = OPER_TYPE;
-           m_tokenBQueue.push(temp);
+           m_tokenBQueue.push_back(temp);
        }
        temp = m_tokenB;
-       m_tokenBQueue.push(temp);
+       m_tokenBQueue.push_back(temp);
        temp = m_tokenBQueue.front();
-       m_tokenBQueue.pop();
+       m_tokenBQueue.pop_front();
        m_tokenB = temp;
    }
 }
diff --git a/trunk/src/jsparser.h b/trunk/src/jsparser.h
index 64708ca..d09edfd 100644
--- a/trunk/src/jsparser.h
+++ b/trunk/src/jsparser.h
@@ -95,7 +95,7 @@ public:
    typedef stack<char> CharStack;
    typedef stack<bool> BoolStack;
    typedef stack<int> IntStack;
-   typedef queue<Token> TokenQueue;
+   typedef deque<Token> TokenQueue;
    typedef map<string, char> StrCharMap;
    typedef set<string> StrSet;

@@ -158,6 +158,8 @@ protected:

    bool GetToken(); // 处理过负数, 正则等等的 GetToken 函数

+   int HasAfter(char* code2Find, char* codeToAvoid, int maxTokens, int maxChars);
+
    void inline StartParse()
    { m_startClock = clock(); }

diff --git a/trunk/src/realjsformatter.cpp b/trunk/src/realjsformatter.cpp
index 9611b60..1cb59f6 100644
--- a/trunk/src/realjsformatter.cpp
+++ b/trunk/src/realjsformatter.cpp
@@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 #include <string>
 #include <cstring>
 #include <iostream>
+#include <sstream>
 #include <ctime>

 #include "realjsformatter.h"
@@ -179,6 +180,9 @@ void RealJSFormatter::PutToken(const Token& token,
        PutChar(token[i]);
    PutChar('\n');*/
    // debug
+   m_nbCharThisLine += leftStyle.length();
+   m_nbCharThisLine += token.code.length();
+   m_nbCharThisLine += rightStyle.length();
    PutString(leftStyle);
    PutString(token);
    PutString(rightStyle);
@@ -343,6 +347,7 @@ void RealJSFormatter::Go()
    bool bHaveNewLine;
    char tokenAFirst;
    char tokenBFirst;
+   m_tokenZ.code = ";";

    StartParse();

@@ -420,6 +425,7 @@ void RealJSFormatter::Go()
            ProcessString(bHaveNewLine, tokenAFirst, tokenBFirst);
            break;
        }
+       m_tokenZ = m_tokenA;
    }

    if(!m_bLineTemplate)
@@ -553,8 +559,12 @@ void RealJSFormatter::ProcessOper(bool bHaveNewLine, char tokenAFirst, char toke
        // 对于 do{} 也一样

        GetStackTop(m_blockStack, topStack);
-       if(topStack != JS_BRACKET && !bHaveNewLine && !IsInlineComment(m_tokenB))
+       if (topStack != JS_BRACKET && !bHaveNewLine && !IsInlineComment(m_tokenB))
+       {
            PutToken(m_tokenA, string(""), strRight.append("\n")); // 如果不是 () 里的 ; 就换行
+           m_lineHasB = false;
+           m_nbCharThisLine = 0;
+       }
        else if(topStack == JS_BRACKET || m_tokenB.type == COMMENT_TYPE_1 ||
            IsInlineComment(m_tokenB))
            PutToken(m_tokenA, string(""), strRight); // (; ) 空格
@@ -571,8 +581,28 @@ void RealJSFormatter::ProcessOper(bool bHaveNewLine, char tokenAFirst, char toke
            --m_nIndents;
            m_blockStack.pop();
        }
-       if(StackTopEq(m_blockStack, JS_BLOCK) && !bHaveNewLine)
-           PutToken(m_tokenA, string(""), strRight.append("\n")); // 如果是 {} 里的
+
+       if (m_compactMode && m_tokenZ.code == "}")
+       {
+           //compact mode only: },"bla" => },\n"bla"
+           PutToken(m_tokenA, string(""), strRight.append("\n"));
+           m_lineHasB = false;
+           m_nbCharThisLine = 0;
+       }
+       else if(StackTopEq(m_blockStack, JS_BLOCK) && !bHaveNewLine)
+           {
+               int ba = HasAfter("{","}",6, 99999);
+               if (m_compactMode && ((/*m_lineHasB &&*/ ba<6) || m_nbCharThisLine>m_maxCharsPerLine))
+               {
+                   //compact mode only: , "bla":{...{ => ,\n "bla":{
+                   PutToken(m_tokenA, string(""), strRight.append("\n"));
+                   m_lineHasB = false;
+                   m_nbCharThisLine = 0;
+               }
+               else
+                   //default path (\n after each ',' or compact mode: no \n after ',' unless special case.
+                   PutToken(m_tokenA, string(""), strRight.append(m_compactMode?"":"\n")); // 如果是 {} 里的
+           }
        else
            PutToken(m_tokenA, string(""), strRight);

@@ -581,6 +611,7 @@ void RealJSFormatter::ProcessOper(bool bHaveNewLine, char tokenAFirst, char toke

    if(m_tokenA.code == "{")
    {
+       m_lineHasB = true;
        GetStackTop(m_blockStack, topStack);
        if(topStack == JS_IF || topStack == JS_FOR ||
            topStack == JS_WHILE || topStack == JS_DO ||
@@ -647,8 +678,22 @@ void RealJSFormatter::ProcessOper(bool bHaveNewLine, char tokenAFirst, char toke
        else
        {
            string strLeft = (m_struOption.eBracNL == NEWLINE_BRAC && !m_bNewLine) ? string("\n") : string("");
-           if(!bHaveNewLine && !IsInlineComment(m_tokenB)) // 需要换行
-               PutToken(m_tokenA, strLeft, strRight.append("\n"));
+           if (!bHaveNewLine && !IsInlineComment(m_tokenB)) // 需要换行
+           {
+               int ba = 9999;
+               if (m_compactMode) ba = HasAfter("}", "{", 40, m_maxCharsPerLine);
+               if (ba<40)
+                   // compact mode only: "bla":{"length":"short"}  ok, no '\n' before }
+                   PutToken(m_tokenA, strLeft, strRight);
+               else
+               {
+                   // compact mode: "bla":{...(very long) => "bla":{\n...(very long)
+                   // or default path
+                   PutToken(m_tokenA, strLeft, strRight.append("\n"));
+                   m_lineHasB = false;
+                   m_nbCharThisLine = 0;
+               }
+           }
            else
                PutToken(m_tokenA, strLeft, strRight);
        }
@@ -718,13 +763,27 @@ void RealJSFormatter::ProcessOper(bool bHaveNewLine, char tokenAFirst, char toke
            }
        }

+
+       // compact_mode: "bla":{"a":1}  ok, no '\n' before }
+       if (m_lineHasB && m_compactMode){
+           PutToken(m_tokenA,string(""),string(""));
+           m_lineHasB = false;
+           return; // }
+       }
+
        string leftStyle("");
-       if(!m_bNewLine)
+       if (!m_bNewLine)
+       {
            leftStyle = "\n";
-       if(m_bEmptyBracket)
+           m_lineHasB = false;
+           m_nbCharThisLine = 0;
+       }
+       if (m_bEmptyBracket)
        {
            leftStyle = "";
            strRight.append("\n");
+           m_lineHasB = false;
+           m_nbCharThisLine = 0;
            m_bEmptyBracket = false;
        }

diff --git a/trunk/src/realjsformatter.h b/trunk/src/realjsformatter.h
index dac83c3..c21de3d 100644
--- a/trunk/src/realjsformatter.h
+++ b/trunk/src/realjsformatter.h
@@ -105,6 +105,15 @@ private:
    // 以下为配置项
    FormatterOption m_struOption;

+   //vars used by compact mode
+   Token m_tokenZ;
+   bool m_lineHasB = false;
+   int m_nbCharThisLine = 0;
+
+   //parameters for compact mode TODO: add them to the ui
+   bool m_compactMode = true;
+   int m_maxCharsPerLine = 180;
+
 private:
    // 阻止拷贝
    RealJSFormatter(const RealJSFormatter&);
-- 
2.5.0.windows.1
sunjw commented 7 years ago

Looks great! Thank you very much. I'll see if we can have this feature.

maf-soft commented 5 years ago

Hi, I was also looking for some "compact" mode. Can you show an example how it looks like?

My idea is to make a very simple option to compact only the deepest level (the leafes) by putting them into one line, if this line would be no longer than x (configurable) characters. This can then be easily disabled by setting x to 0.

Example:

{
  "List": [
    {"aaa": 1, "bbb": 2, "ccc": 3},
    {"aaa": 4, "bbb": 5, "ccc": 6},
    {"aaa": 7, "bbb": 8, "ccc": 9}
  ]
}

or (less change to current version / easier to do):

{
  "List": [{
    "aaa": 1, "bbb": 2, "ccc": 3},{
    "aaa": 4, "bbb": 5, "ccc": 6},{
    "aaa": 7, "bbb": 8, "ccc": 9}
  ]
}
supermerill commented 5 years ago

an exemple:


{
    "name": "vkl-graph", "version": "1.3.0-alpha", "description": "Graphs jQPlot binding for GWT", "homepage": "http://vekiaopensource.github.io/vkl-graph/", "keywords": ["graphs", "gwt", "jQPlot"],
    "author": "Steeve Vandecappelle <me@mizore.fr>", "private": true,
    "contributors": [{ "name": ""}],
    "dependencies": { "log4js": ">=0.6.6", "gift": "*", "temp": "~0.7.0", "underscore": "*", "ncp": "*", "rmdir": "*"},
    "bin": "./fetch.js",
    "scripts": { "checkout": "node fetch.js"},
    "repository": { "type": "git", "url": "https://github.com/VekiaOpenSource/vkl-graph.git"}
}