diff --git a/src/Edit.c b/src/Edit.c index ba0cb979b9..95ab59888e 100644 --- a/src/Edit.c +++ b/src/Edit.c @@ -2289,6 +2289,168 @@ void EditBase64Decode(bool decodeAsHex) { EditReplaceMainSelection(outLen, (char *)output); } NP2HeapFree(output); +} + +// indent function for json +static void append_indent(char *result, int number) { + for (int i = 0; i < number * JSON_INDENT; ++i) { + result[strlen(result)] = ' '; + } +} + +// format or compress json +void EditJSONFormat(bool isFormat) { + const size_t len = SciCall_GetSelTextLength(); + if (len == 0) { + return; + } + + char *json = (char *)NP2HeapAlloc(len + 1); + SciCall_GetSelBytes(json); + + if (isFormat) { + long long length = strlen(json); + bool is_escape_mode = false; + int indent_number = 0; + char current_char; + char wrap_char = '\0'; + long long size = (length * 2) + 1; + char *result = (char *)malloc(size); + memset(result, 0, size); + + long long result_index = 0; + + for (long i = 0; i < length; i++) { + current_char = json[i]; + + if (wrap_char == '\0' && + (current_char == '\t' || current_char == '\n' || current_char == '\r' || current_char == ' ')) { + continue; + } + if (wrap_char == '\0' && current_char == ':') { + result[result_index++] = current_char; + result[result_index++] = ' '; + continue; + } + + if (current_char == '"') { + if (wrap_char == '\0') { + wrap_char = current_char; + } else if (is_escape_mode) { + is_escape_mode = false; + } else { + wrap_char = '\0'; + } + + result[result_index++] = current_char; + continue; + } + + if (current_char == '\\') { + if (wrap_char != '\0') { + is_escape_mode = !is_escape_mode; + } + result[result_index++] = current_char; + continue; + } + + if (wrap_char != '\0') { + result[result_index++] = current_char; + continue; + } + + if (current_char == '[' || current_char == '{') { + result[result_index++] = current_char; + result[result_index++] = '\n'; + indent_number++; + append_indent(result + result_index, indent_number); + result_index += indent_number * JSON_INDENT; + continue; + } + + if (current_char == ']' || current_char == '}') { + result[result_index++] = '\n'; + indent_number--; + append_indent(result + result_index, indent_number); + result_index += indent_number * JSON_INDENT; + result[result_index++] = current_char; + continue; + } + + if (current_char == ',') { + result[result_index++] = current_char; + result[result_index++] = '\n'; + append_indent(result + result_index, indent_number); + result_index += indent_number * JSON_INDENT; + continue; + } + + result[result_index++] = current_char; + + if (result_index + 1 >= size) { + size = result_index += size / 2; + char *new_result = realloc(result, size); + if (new_result == NULL) { + fprintf(stderr, "Error: Failed to reallocate memory in format_json() loop.\n"); + free(result); + return; + } else { + result = new_result; + } + } + } + + char *new_result = realloc(result, result_index); + if (new_result == NULL) { + fprintf(stderr, "Error: Failed to reallocate memory in format_json().\n"); + free(result); + return; + } else { + result[result_index] = '\0'; + result = new_result; + } + + EditReplaceMainSelection(strlen(result), result); + NP2HeapFree(json); + } else { + long long length = strlen(json); + bool isWarp = false; + char *result = (char *)malloc(length + 1); // 分配额外空间,同时留一个位置给字符串结束符'\0' + memset(result, 0, length + 1); + + char current_char; + long long result_index = 0; + for (int i = 0; i < length; i++) { + current_char = json[i]; + + if (current_char == '"') { + if (i > 0 && json[i - 1] != '\\' || (i > 1 && json[i - 2] == '\\')) { + isWarp = !isWarp; + } + } + + if (!isWarp) { + if (current_char == '\t' || current_char == '\n' || current_char == '\r' || current_char == ' ') { + continue; + } + } + + result[result_index++] = current_char; + } + + result[result_index] = '\0'; + char *new_result = realloc(result, result_index + 1); + if (new_result == NULL) { + fprintf(stderr, "Error: Failed to reallocate memory in compress_json().\n"); + free(result); + return; + } else { + result = new_result; + } + + EditReplaceMainSelection(strlen(result), result); + NP2HeapFree(json); + } } //============================================================================= diff --git a/src/Edit.h b/src/Edit.h index f3ee00c4b2..6261b666be 100644 --- a/src/Edit.h +++ b/src/Edit.h @@ -32,6 +32,7 @@ #define NP2_MarkAllBookmark 0x00002000 #define NP2_MarkAllSelectAll 0x00004000 #define NP2_FromFindAll 0x00008000 +#define JSON_INDENT 4 typedef struct EDITFINDREPLACE { char szFind[512]; @@ -154,6 +155,7 @@ typedef enum Base64EncodingFlag { } Base64EncodingFlag; void EditBase64Encode(Base64EncodingFlag encodingFlag); void EditBase64Decode(bool decodeAsHex); +void EditJSONFormat(bool isFormat); void EditConvertNumRadix(int radix); void EditModifyNumber(bool bIncrease); diff --git a/src/Notepad2.c b/src/Notepad2.c index 138d696ce2..9fee26bcd2 100644 --- a/src/Notepad2.c +++ b/src/Notepad2.c @@ -2546,7 +2546,10 @@ void MsgInitMenu(HWND hwnd, WPARAM wParam, LPARAM lParam) { EnableCmd(hmenu, IDM_EDIT_NUM2HEX, i); EnableCmd(hmenu, IDM_EDIT_NUM2DEC, i); EnableCmd(hmenu, IDM_EDIT_NUM2BIN, i); - EnableCmd(hmenu, IDM_EDIT_NUM2OCT, i); + EnableCmd(hmenu, IDM_EDIT_NUM2OCT, i); + + EnableCmd(hmenu, IDM_EDIT_JSON_FORMAT, i); + EnableCmd(hmenu, IDM_EDIT_JSON_COMPRESS, i); //EnableCmd(hmenu, IDM_EDIT_INCREASENUM, i); //EnableCmd(hmenu, IDM_EDIT_DECREASENUM, i); @@ -3785,6 +3788,13 @@ LRESULT MsgCommand(HWND hwnd, WPARAM wParam, LPARAM lParam) { BeginWaitCursor(); EditBase64Decode(LOWORD(wParam) == IDM_EDIT_BASE64_DECODE_AS_HEX); EndWaitCursor(); + break; + + case IDM_EDIT_JSON_FORMAT: + case IDM_EDIT_JSON_COMPRESS: + BeginWaitCursor(); + EditJSONFormat(LOWORD(wParam) == IDM_EDIT_JSON_FORMAT); + EndWaitCursor(); break; case IDM_EDIT_NUM2HEX: diff --git a/src/Notepad2.rc b/src/Notepad2.rc index da82093ab6..ef16fa47a4 100644 --- a/src/Notepad2.rc +++ b/src/Notepad2.rc @@ -718,6 +718,11 @@ BEGIN MENUITEM "Custom Action &1\tCtrl+Shift+1", CMD_CUSTOM_ACTION1 MENUITEM "Custom Action &2\tCtrl+Shift+2", CMD_CUSTOM_ACTION2 END + POPUP "&JSON" + BEGIN + MENUITEM "JSON &Format", IDM_EDIT_JSON_FORMAT + MENUITEM "JSON &Compress", IDM_EDIT_JSON_COMPRESS + END POPUP "&Base64" BEGIN MENUITEM "Standard &Encode", IDM_EDIT_BASE64_ENCODE diff --git a/src/resource.h b/src/resource.h index 2fff69c431..fef7abb1d1 100644 --- a/src/resource.h +++ b/src/resource.h @@ -758,7 +758,9 @@ #define IDM_EDIT_BASE64_SAFE_ENCODE 40495 #define IDM_EDIT_BASE64_HTML_EMBEDDED_IMAGE 40496 #define IDM_EDIT_BASE64_DECODE 40497 -#define IDM_EDIT_BASE64_DECODE_AS_HEX 40498 +#define IDM_EDIT_BASE64_DECODE_AS_HEX 40498 +#define IDM_EDIT_JSON_FORMAT 40499 +#define IDM_EDIT_JSON_COMPRESS 40509 #define IDM_HELP_ABOUT 40500 // F1 #define IDM_CMDLINE_HELP 40501