css compression/decompression
Posted: Sat Aug 31, 2024 1:54 pm
The uncompression code is primitive, as it works only after compression by my algorithm. At the moment, decompression does not correct decompressed code and does not process comments, since they are considered to be deleted after compression.
It started with a question from here
Download: upload.ee, yandex (the files are always newer)
ini file (must have the same name as the exe file):
source = path to source file
destination = path to the resulting file being created
flag = 6 - css formatting flags (see below)
open = 1 - open the resulting file for viewing in the associated program
msg = 1 - messages
Flags of the ini file (can be a combination-sum of flags):
1 - CSS compression. Flags 2, 4, 8 do not work in this mode.
2 - opening curly brace "{" on a new line
4 - after the comma "," in the class listing, there will be a line break instead of a space. This makes the classes a vertical list and is easier to read.
8 - (the option is disabled for now) there is no space inside the curly braces {...} after the colon ":" (separation of parameter and value)
16 - Convert rgb(x,x,x) to #hex
128 - disables deleting comments. Works with flag 1.
Command line: The "flag source_path destination_path" is passed on the command line. If the file is not transferred, a file selection window opens. If a file is selected, a save dialog is created in the same folder as a file with index "_1". The command line takes precedence over the ini file.
css_tidy
It started with a question from here
Download: upload.ee, yandex (the files are always newer)
ini file (must have the same name as the exe file):
source = path to source file
destination = path to the resulting file being created
flag = 6 - css formatting flags (see below)
open = 1 - open the resulting file for viewing in the associated program
msg = 1 - messages
Flags of the ini file (can be a combination-sum of flags):
1 - CSS compression. Flags 2, 4, 8 do not work in this mode.
2 - opening curly brace "{" on a new line
4 - after the comma "," in the class listing, there will be a line break instead of a space. This makes the classes a vertical list and is easier to read.
8 - (the option is disabled for now) there is no space inside the curly braces {...} after the colon ":" (separation of parameter and value)
16 - Convert rgb(x,x,x) to #hex
128 - disables deleting comments. Works with flag 1.
Command line: The "flag source_path destination_path" is passed on the command line. If the file is not transferred, a file selection window opens. If a file is selected, a save dialog is created in the same folder as a file with index "_1". The command line takes precedence over the ini file.
css_tidy
Code: Select all
;- TOP
; AZJIO 2024.09.02 - 2024.09.24
EnableExplicit
;- ● Global
Global NewList TextList.s()
Global Dim Tab.s(1)
Tab(1) = #TAB$
Global g_Format, flag, Error, open, msg, StartTime
Global source$, destination$, current$, ext$, Message$
;- ● Define
Define Len, *Point
Define Result.string
Define CountPP
Define tmp$
; https://www.purebasic.fr/english/viewtopic.php?p=478874
XIncludeFile "AutoDetectTextEncoding_Trim.pbi"
Procedure.s RTrimChar(String$, TrimChar$ = " " + #TAB$ + #CRLF$ + #FF$ + #VT$)
Protected Len2, Blen, i
Protected *jc0, *c.Character, *jc.Character
Len2 = Len(String$)
Blen = StringByteLength(String$)
If Not Asc(String$)
ProcedureReturn ""
EndIf
*c = @String$ + Blen - SizeOf(Character)
*jc0 = @TrimChar$
For i = Len2 To 1 Step - 1
*jc = *jc0
While *jc\c
If *c\c = *jc\c
*c\c = 0
Break
EndIf
*jc + SizeOf(Character)
Wend
If *c\c
Break
EndIf
*c - SizeOf(Character)
Next
ProcedureReturn String$
EndProcedure
Procedure ForceDirectories(Dir.s)
Static tmpDir.s, Init
Protected result
If Asc(Dir) ; если что-то есть
If Not Init
tmpDir = Dir
Init = 1
EndIf
Dir = RTrim(Dir, #PS$) ; убираем последний слеш, не делая лишние проверки
; если папка существует или дошли до корневой, то
If FileSize(Dir) = -2 Or (Len(Dir) < 3) Or GetPathPart(Dir) = Dir
If FileSize(tmpDir) = -2
result = -1 ; попробуем использовать -1 в качестве "путь уже создан"
EndIf
tmpDir = ""
Init = 0
ProcedureReturn result ; если это папка, то возврат будет 1
EndIf
ForceDirectories(GetPathPart(Dir))
ProcedureReturn CreateDirectory(Dir)
Else
ProcedureReturn 0
EndIf
EndProcedure
; Чтение файла в гаджет
Procedure.s OpenFileToGadget(FilePath$)
Protected length, oFile, bytes, *mem, Text$
oFile = ReadFile(#PB_Any, FilePath$)
If oFile
g_Format = ReadStringFormat(oFile)
length = Lof(oFile)
*mem = AllocateMemory(length)
If *mem
bytes = ReadData(oFile, *mem, length)
If bytes
If g_Format = #PB_Ascii
g_Format = dte::detectTextEncodingInBuffer(*mem, bytes, 0)
If g_Format = #PB_Ascii
Text$ = PeekS(*mem, bytes, #PB_Ascii)
Else
Text$ = PeekS(*mem, bytes, #PB_UTF8) ; если UTF8 без BOM
EndIf
Else
; тут не уверен, PeekS() поддерживает #PB_Unicode,
; а ReadStringFormat() может дать #PB_UTF16BE, #PB_UTF32, #PB_UTF32BE
; хотя эти форматы не популярны скорее не встретятся, и надо сделать на них игнор
Text$ = PeekS(*mem, bytes, g_Format)
EndIf
EndIf
FreeMemory(*mem)
EndIf
CloseFile(oFile)
EndIf
ProcedureReturn Text$
EndProcedure
Procedure cssCompression(*c.Character)
Protected sz = SizeOf(Character)
Protected OpenBrace, OpenSquareBracket
Protected *tmp, *start
If *c = 0 Or *c\c = 0
MessageRequester("Ошибка", "Данные пусты")
ProcedureReturn
; ElseIf *c\c = '{' ; защита уже сделана
; MessageRequester("Ошибка", "{ - фигурная скобка не может быть первым символом соответсвенно невозможно осуществить просмотр назад")
; ProcedureReturn
EndIf
*start = *c
; Удаление стартовых пробелов
While *c\c = 32 Or (*c\c > 8 And *c\c < 14)
*c\c = 1
*c + sz
Wend
While *c\c
Select *c\c
;- /
Case '/' ; проверка комментариев, если найдено то затираем псевдо-пусто-символом
If flag & 128 ; если флаг 128, то не удаляем комментарии
*c + sz
If *c\c = '*'
*c + sz
While *c\c
If *c\c = '*'
*c + sz
If *c\c = '/'
Break
EndIf
*c - sz
EndIf
*c + sz
Wend
If *c\c = 0 ; проверка если комент не закрыт в конце файла
Break
EndIf
Else
Continue
EndIf
Else
*c + sz
If *c\c = '*'
*c - sz
*c\c = 1
*c + sz
*c\c = 1
*c + sz
While *c\c
If *c\c = '*'
*c + sz
If *c\c = '/'
*c - sz
*c\c = 1
*c + sz
*c\c = 1
*c + sz
While *c\c = 32 Or (*c\c > 8 And *c\c < 14)
*c\c = 1
*c + sz
Wend
*c - sz
Break
EndIf
*c - sz
EndIf
*c\c = 1
*c + sz
Wend
Else
*c - sz
EndIf
EndIf
;- '
Case 39 ; проверка апострофа, идём до закрывающего апострофа
; *tmp = *c
*c + sz
While *c\c
If *c\c = 39
; Debug PeekS(*tmp, (*c - *tmp) / 2 + 1, #PB_Unicode)
Break
EndIf
If *c\c > 8 And *c\c < 14
; Debug PeekS(*tmp, (*c - *tmp) / 2, #PB_Unicode)
*c\c = 32
Error + 1
Break
EndIf
*c + sz
Wend
;- "
Case 34 ; проверка кавычки, идём до закрывающей кавычки
; *tmp = *c
*c + sz
While *c\c
If *c\c = 34
; Debug PeekS(*tmp, (*c - *tmp) / 2 + 1, #PB_Unicode)
Break
ElseIf *c\c > 8 And *c\c < 14
; Debug PeekS(*tmp, (*c - *tmp) / 2, #PB_Unicode)
*c\c = 32
Error + 1
Break
Else
*c + sz
EndIf
Wend
;- [ ]
Case '['
OpenSquareBracket = 1
Case ']'
OpenSquareBracket = 0
;- !
Case '!'
If OpenBrace And CompareMemoryString(*c , @"!important", #PB_String_NoCaseAscii, 10) = #PB_String_Equal
; проверка пробелов назад
*tmp = *c
*c - sz
While *c>=*start And (*c\c = 32 Or (*c\c > 8 And *c\c < 14))
*c\c = 1
*c - sz
Wend
*c = *tmp + (10 * sz)
Continue
EndIf
;- ,:
Case ',', ':';, ')'
If OpenSquareBracket = 0; And OpenBrace = 0
*c + sz
While *c\c = 32 Or (*c\c > 8 And *c\c < 14)
*c\c = 1
*c + sz
Wend
*c - sz
EndIf
;- {
Case '{'
OpenBrace = 1
; проверка пробелов назад
*tmp = *c
*c - sz
While *c>=*start And (*c\c = 32 Or *c\c = 1 Or (*c\c > 8 And *c\c < 14))
*c\c = 1
*c - sz
Wend
*c = *tmp
; проверка пробелов вперёд
*c + sz
While *c\c = 32 Or (*c\c > 8 And *c\c < 14)
*c\c = 1
*c + sz
Wend
*c - sz
;- }
Case '}'
OpenBrace = 0
; проверка пробелов назад
*tmp = *c
*c - sz
While *c>=*start And (*c\c = 32 Or *c\c = ';' Or *c\c = 1 Or (*c\c > 8 And *c\c < 14))
*c\c = 1
*c - sz
Wend
*c = *tmp
; проверка пробелов вперёд
*c + sz
While *c\c = 32 Or (*c\c > 8 And *c\c < 14)
*c\c = 1
*c + sz
Wend
*c - sz
;- ;
Case ';' ; разделитель параметров в css
If OpenBrace ; внутри фигурных скобок
*c + sz
While *c\c = 32 Or *c\c = ';' Or (*c\c > 8 And *c\c < 14)
*c\c = 1
*c + sz
Wend
*c - sz
EndIf
;- Space, Tab, CR
Case 32, 9 To 13 ; пробел и табуляция и переносы строк
If *c\c <> 32
OpenSquareBracket = 0
EndIf
*c\c = 32 ; заменяем любой перенос пробелом
; If OpenBrace
; *c\c = 1
; Else
*c + sz
While *c\c = 32 Or (*c\c > 8 And *c\c < 14) ; удаляем повтор пробельных символов
*c\c = 1
*c + sz
Wend
*c - sz
; EndIf
EndSelect
*c + sz
Wend
EndProcedure
Procedure cssTidy(*c.Character)
Protected sz = SizeOf(Character)
Protected OpenBrace, OpenSquareBracket, CountBrace
Protected *tmp, *beginning
If *c = 0 Or *c\c = 0
MessageRequester("Ошибка", "Данные пусты")
ProcedureReturn
; ElseIf *c\c = '{' ; защита уже сделана
; MessageRequester("Ошибка", "{ - фигурная скобка не может быть первым символом соответсвенно невозможно осуществить просмотр назад")
; ProcedureReturn
EndIf
*beginning = *c
; Удаление стартовых пробелов
; While *c\c = 32 Or (*c\c > 8 And *c\c < 14)
; *c\c = 1
; *c + sz
; Wend
While *c\c
Select *c\c
;- comment
Case '/' ; проверка комментариев, если найдено то ищем закрытие
*c + sz
If *c\c = '*'
*c + sz
While *c\c
If *c\c = '*'
*c + sz
If *c\c = '/'
Break
EndIf
*c - sz
EndIf
*c + sz
Wend
If *c\c = 0 ; проверка если комент не закрыт в конце файла
Break
EndIf
Else
Continue
EndIf
;- '
Case 39 ; проверка апострофа, идём до закрывающего апострофа
; *tmp = *c
*c + sz
While *c\c
If *c\c = 39
; Debug PeekS(*tmp, (*c - *tmp) / 2 + 1, #PB_Unicode)
Break
EndIf
If *c\c > 8 And *c\c < 14
; Debug PeekS(*tmp, (*c - *tmp) / 2, #PB_Unicode)
Error + 1
Break
EndIf
*c + sz
Wend
;- "
Case 34 ; проверка кавычки, идём до закрывающей кавычки
; *tmp = *c
*c + sz
While *c\c
If *c\c = 34
; Debug PeekS(*tmp, (*c - *tmp) / 2 + 1, #PB_Unicode)
Break
ElseIf *c\c > 8 And *c\c < 14
; Debug PeekS(*tmp, (*c - *tmp) / 2, #PB_Unicode)
Error + 1
Break
Else
*c + sz
EndIf
Wend
; Case '['
; OpenSquareBracket = 1
; Case ']'
; OpenSquareBracket = 0
;- ,
Case ','
*c\c = 0
*c + sz
AddElement(TextList())
TextList() = PeekS(*beginning)
AddElement(TextList())
While *c\c = 32 Or (*c\c > 8 And *c\c < 14)
*c + sz
Wend
; без этого OpenBrace перечисление шрифтов делает столбиком. Исправить.
; С другой стороны вложенные классы перестанет обрабатывать
If flag & 4 And Not OpenBrace
TextList() = "," + #CRLF$
ElseIf *c\c = ' '
TextList() = ","
Else
TextList() = ", "
EndIf
*beginning = *c
Continue
;- :
Case ':'
If OpenBrace
*c + sz
If *c\c = ':' Or *c\c = ' '
*c + sz
Continue
EndIf
*c - sz
*c - sz
; If *c\c = ':' Or *c\c = '{' Or *c\c = '}' Or *c\c = ';' Or *c\c = ')' Or *c\c = ' ' Or (*c\c > 8 And *c\c < 14)
; *c + sz
; ; *c + sz
; ; Continue
; Else
; *c + sz
; *c\c = 0
; *c + sz
; AddElement(TextList())
; TextList() = PeekS(*beginning)
; AddElement(TextList())
; TextList() = ": "
; *beginning = *c
; Continue
; EndIf
If (*c\c > 96 And *c\c < 123) And CompareMemoryString(*c + sz * 2, @"not", #PB_String_NoCaseAscii, 3) <> #PB_String_Equal
*c + sz
*c\c = 0
*c + sz
AddElement(TextList())
TextList() = PeekS(*beginning)
AddElement(TextList())
TextList() = ": "
*beginning = *c
Continue
Else
*c + sz
EndIf
EndIf
; If OpenBrace And flag ! 8 ; внутри фигурных скобок
; *c + sz
; If *c\c = ':'
; *c + sz
; Continue
; ElseIf CompareMemoryString(*c , @"not", #PB_String_NoCaseAscii, 3) = #PB_String_Equal
; *c + sz * 3
; Continue
; ElseIf CompareMemoryString(*c , @"root", #PB_String_NoCaseAscii, 4) = #PB_String_Equal
; *c + sz * 4
; Continue
; ; ElseIf PeekS(*c, 3) = "not"
; ; *c + sz * 3
; ; Continue
; ; ElseIf PeekS(*c, 3) = "root"
; ; *c + sz * 4
; ; Continue
; ; ElseIf *c\c = 'n'
; ; *c + sz
; Else
; *c - sz
; EndIf
; EndIf
;- ;
Case ';'
*c\c = 0
*c + sz
AddElement(TextList())
TextList() = PeekS(*beginning)
AddElement(TextList())
If OpenBrace
TextList() = ";" + #CRLF$ + Tab(OpenBrace)
Else
TextList() = ";" + #CRLF$ + Tab(OpenBrace)
EndIf
While *c\c = 32 Or *c\c = ';' Or (*c\c > 8 And *c\c < 14)
*c + sz
Wend
*beginning = *c
Continue
;- !
Case '!'
If OpenBrace And CompareMemoryString(*c , @"!important", #PB_String_NoCaseAscii, 10) = #PB_String_Equal
*c - sz
If *c\c <> 32
*c + sz
*c\c = 0
AddElement(TextList())
TextList() = PeekS(*beginning)
AddElement(TextList())
TextList() = " !important"
; проверка пробелов назад
*c + 10 * sz
*beginning = *c
Continue
Else
*c + sz
EndIf
EndIf
;- (
Case '(' ; при открывающей скобке ищем закрывающую
*c + sz
While *c\c
Select *c\c
Case '(' ; если опять открывается, то используем счётчик, чтобы искать последнюю закрывющуюся.
CountBrace + 1
Case ')'
If CountBrace
CountBrace - 1
Else
If OpenBrace
*c\c = 0
*c + sz
AddElement(TextList())
TextList() = PeekS(*beginning)
AddElement(TextList())
If *c\c = ';' Or *c\c = ':' Or *c\c = ' ' ; Or *c\c = '{'
TextList() = ")"
Else
TextList() = ") "
EndIf
*beginning = *c
*c - sz
EndIf
Break
EndIf
Case 9 To 13
Error + 1
Break
EndSelect
*c + sz
Wend
; )
; Case ')'
;- {
Case '{'
OpenBrace + 1
If OpenBrace > ArraySize(Tab())
ReDim Tab(OpenBrace)
Tab(OpenBrace) = LSet("", OpenBrace, #TAB$)
EndIf
*c\c = 0
*c + sz
AddElement(TextList())
TextList() = PeekS(*beginning)
TextList() = RTrimChar(TextList()) ; не оптимизировано, это можно сделать тут же без функции
AddElement(TextList())
If flag & 2
TextList() = #CRLF$ + "{" + #CRLF$ + Tab(OpenBrace)
Else
TextList() = " {" + #CRLF$ + Tab(OpenBrace)
EndIf
While *c\c = 32 Or *c\c = ';' Or (*c\c > 8 And *c\c < 14)
*c + sz
Wend
*beginning = *c
Continue
;- }
Case '}'
OpenBrace - 1
If OpenBrace < 0
OpenBrace = 0
EndIf
*c\c = 0
*c + sz
TextList() = RTrimChar(TextList()) ; так как здесь добавление отступов, то проверяем что у предыдущего не было добавлено
AddElement(TextList())
TextList() = PeekS(*beginning)
TextList() = RTrimChar(TextList())
AddElement(TextList())
TextList() = #CRLF$ + Tab(OpenBrace) + "}"
While *c\c = 32 Or (*c\c > 8 And *c\c < 14)
*c + sz
Wend
While *c\c = '}'
OpenBrace - 1
If OpenBrace < 0
OpenBrace = 0
EndIf
TextList() + #CRLF$ + Tab(OpenBrace) + "}"
*c + sz
While *c\c = 32 Or (*c\c > 8 And *c\c < 14)
*c + sz
Wend
Wend
TextList() + #CRLF$ + Tab(OpenBrace); + #CRLF$
*beginning = *c
Continue
EndSelect
*c + sz
Wend
EndProcedure
Structure RGBA
StructureUnion
color.l
b.a[4]
EndStructureUnion
EndStructure
Procedure RGBtoHEX(*text.String)
Protected *c.Character, Color.RGBA
Protected *StartNum, *Start0, *Start00
Protected i, count, tmp$
Protected sz = SizeOf(Character)
; Debug *text\s
*c = @*text\s
*Start00 = *c
While *c\c
If *c\c = 'r'
*Start0 = *c
*c - sz
If *c >= *Start00 And (*c\c = ' ' Or *c\c = ':' Or *c\c = #TAB)
*c + sz * 2
Else
*c + sz * 2
Continue
EndIf
If *c\c = 'g'
*c + sz
Else
Continue
EndIf
If *c\c = 'b'
*c + sz
Else
Continue
EndIf
While *c\c = 32
*c + sz
Wend
If *c\c = 0
Break
EndIf
If *c\c <> '('
*c + sz
Continue
EndIf
*c + sz
While *c\c = 32
*c + sz
Wend
If *c\c = 0
Break
EndIf
*StartNum = *c
While *c\c >= '0' And *c\c <= '9'
*c + sz
Wend
; Debug *StartNum
; Debug *c
If *StartNum <> *c
; Debug PeekS(*StartNum, (*c - *StartNum) / sz)
; red0 = Val(PeekS(*StartNum, (*c - *StartNum) / sz))
Color\b.a[2] = Val(PeekS(*StartNum, (*c - *StartNum) / sz))
; Debug red0
Else
*c + sz
Continue
EndIf
While *c\c = 32
*c + sz
Wend
If *c\c = 0
Break
EndIf
If *c\c <> ','
*c + sz
Continue
EndIf
*c + sz
While *c\c = 32
*c + sz
Wend
If *c\c = 0
Break
EndIf
*StartNum = *c
While *c\c >= '0' And *c\c <= '9'
*c + sz
Wend
; Debug *StartNum
; Debug *c
If *StartNum <> *c
; Debug PeekS(*StartNum, (*c - *StartNum) / sz)
; green0 = Val(PeekS(*StartNum, (*c - *StartNum) / sz))
Color\b.a[1] = Val(PeekS(*StartNum, (*c - *StartNum) / sz))
; Debug green0
Else
*c + sz
Continue
EndIf
While *c\c = 32
*c + sz
Wend
If *c\c = 0
Break
EndIf
If *c\c <> ','
*c + sz
Continue
EndIf
*c + sz
While *c\c = 32
*c + sz
Wend
If *c\c = 0
Break
EndIf
*StartNum = *c
While *c\c >= '0' And *c\c <= '9'
*c + sz
Wend
; Debug *StartNum
; Debug *c
If *StartNum <> *c
; Debug PeekS(*StartNum, (*c - *StartNum) / sz)
; blue0 = Val(PeekS(*StartNum, (*c - *StartNum) / sz))
Color\b.a[0] = Val(PeekS(*StartNum, (*c - *StartNum) / sz))
; Debug blue0
Else
*c + sz
Continue
EndIf
While *c\c = 32
*c + sz
Wend
If *c\c = 0
Break
EndIf
If *c\c <> ')'
*c + sz
Continue
EndIf
For i = *Start0 To *c Step SizeOf(Character)
PokeA(i, 1)
Next
count = 0
For i = 0 To 2
If Hex(Color\b[i] >> 4) = Hex(Color\b[i] & $F)
count + 1
EndIf
Next
If count = 3
tmp$ = "#" + Hex(Color\b[0] >> 4) + Hex(Color\b[1] >> 4) + Hex(Color\b[2] >> 4)
Else
tmp$ = "#" + RSet(Hex(Color\color), 6, "0")
EndIf
CopyMemory(@tmp$, *Start0, StringByteLength(tmp$))
EndIf
*c + sz
Wend
*text\s = ReplaceString(*text\s, Chr(1), "")
; ProcedureReturn text$
EndProcedure
current$ = GetPathPart(ProgramFilename())
; Global ini$ = current$ + "css_parser_decompression.ini"
Global ini$ = Left(ProgramFilename(), Len(ProgramFilename()) - 3) + "ini"
; чтение параметров ком-строки
CountPP = CountProgramParameters()
If CountPP
flag = Val(ProgramParameter())
If CountPP > 1
source$ = ProgramParameter()
If CountPP > 2
destination$ = ProgramParameter()
EndIf
EndIf
Else
; если нет параметров, то читаем ini-файл
;- ● ini
If OpenPreferences(ini$)
source$ = ReadPreferenceString("source", "")
destination$ = ReadPreferenceString("destination", "")
flag = ReadPreferenceInteger("flag", 0)
open = ReadPreferenceInteger("open", 0)
msg = ReadPreferenceInteger("msg", 0)
ClosePreferences()
EndIf
EndIf
If flag & 1024
msg | 1
EndIf
If flag & 2048
msg | 2
EndIf
If flag & 4096
msg | 4
EndIf
If flag & 8192
open = 1
EndIf
; Если не получили пути, то открываем диалоговое окно выбора.
If Not Asc(source$) Or FileSize(source$) < 0
Debug "source$ = " + source$
source$ = OpenFileRequester("", current$, "*.css|*.css|*.*|*.*", 0)
If Not Asc(source$) Or FileSize(source$) < 0
End ; если выбор отменён, то закрываем программу
EndIf
EndIf
ext$ = GetExtensionPart(source$)
; Если нет пути сохранения или не создан путь к файлу или имя файла содержит некорректные символы, то пытаемся получить путь через диалог открытия файла
If Not Asc(destination$) Or Not ForceDirectories(GetPathPart(destination$)) Or Not CheckFilename(GetFilePart(destination$))
Debug "destination$ = " + destination$
destination$ = Left(source$, Len(source$) - Len(ext$) - 1) + "_2." + ext$ ; формируем путь к файлу для сохранения данных на основе исходного
destination$ = SaveFileRequester("", destination$, "*." + ext$ + "|*." + ext$ + "|*.*|*.*", 0)
If Not Asc(destination$) Or FileSize(GetPathPart(destination$)) <> -2
Debug "неудача-destination$ = " + destination$
End ; если выбор отменён, то закрываем программу
EndIf
EndIf
; Если исходный файл не существует или файл сохранения игнорирован, то завершение программы, дальнейшее выполнятся не будет
; ClearDebugOutput()
; Debug "source$ = " + source$
; Debug "destination$ = " + destination$
Enumeration
#ch1
#ch2
#ch4
#ch16
#ch128
#chmsg1
#chmsg2
#chmsg4
#btnOK
#btnOpen1
#btnOpen2
#fieldPath1
#fieldPath2
#chOpen
EndEnumeration
;-┌──GUI──┐
If flag & 512 And OpenWindow(0, 0, 0, 420, 430, "Настройки css tidy", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_MinimizeGadget)
CheckBoxGadget(#ch1, 10, 10, 400, 30, "1 - Сжатие (удаление пробелов)")
CheckBoxGadget(#ch2, 10, 40, 400, 30, "2 - Фигурная скобка '{' на отдельной строке")
CheckBoxGadget(#ch4, 10, 70, 400, 30, "4 - Списки классов в столбик, перенос после ','")
CheckBoxGadget(#ch16, 10, 100, 400, 30, "16 - Преобразовать rgb(x,x,x) в #hex")
CheckBoxGadget(#ch128, 10, 130, 400, 30, "128 - не удалять комментарии при сжатии")
CheckBoxGadget(#chmsg1, 10, 170, 400, 30, "1 - показать ошибки незавершённой кавычки")
CheckBoxGadget(#chmsg2, 10, 200, 400, 30, "2 - показать время выполнения обработки css")
CheckBoxGadget(#chmsg4, 10, 230, 400, 30, "4 - показать пути")
CheckBoxGadget(#chOpen, 10, 270, 400, 30, "Открыть файл после обработки")
If flag & 1
SetGadgetState(#ch1, #PB_Checkbox_Checked)
EndIf
If flag & 2
SetGadgetState(#ch2, #PB_Checkbox_Checked)
EndIf
If flag & 4
SetGadgetState(#ch4, #PB_Checkbox_Checked)
EndIf
If flag & 16
SetGadgetState(#ch16, #PB_Checkbox_Checked)
EndIf
If flag & 128
SetGadgetState(#ch128, #PB_Checkbox_Checked)
EndIf
If msg & 1
SetGadgetState(#chmsg1, #PB_Checkbox_Checked)
EndIf
If msg & 2
SetGadgetState(#chmsg2, #PB_Checkbox_Checked)
EndIf
If msg & 4
SetGadgetState(#chmsg4, #PB_Checkbox_Checked)
EndIf
If open
SetGadgetState(#chOpen, #PB_Checkbox_Checked)
EndIf
StringGadget(#fieldPath1, 10, 310, 400 - 26, 26, source$)
StringGadget(#fieldPath2, 10, 350, 400 - 26, 26, destination$)
ButtonGadget(#btnOpen1, 420 - 36, 310, 26, 26, Chr($2026)) ; … (обзор)
ButtonGadget(#btnOpen2, 420 - 36, 350, 26, 26, Chr($2026)) ; … (обзор)
ButtonGadget(#btnOK, 300, 383, 111, 40, "OK")
;-┌──Loop──┐
Repeat
Select WaitWindowEvent()
Case #PB_Event_Gadget
Select EventGadget()
Case #btnOK
Break
Case #btnOpen1
tmp$ = OpenFileRequester("", current$, "*.css|*.css|*.*|*.*", 0)
If Asc(tmp$)
SetGadgetText(#fieldPath1, tmp$)
EndIf
Case #btnOpen2
tmp$ = SaveFileRequester("", destination$, "*." + ext$ + "|*." + ext$ + "|*.*|*.*", 0)
If Asc(tmp$)
SetGadgetText(#fieldPath2, tmp$)
EndIf
EndSelect
Case #PB_Event_CloseWindow ; тоже что отмена, закрытие окна ничего не делает
CloseWindow(0)
End
EndSelect
ForEver
;-└──Loop──┘
source$ = GetGadgetText(#fieldPath1)
If Not Asc(source$) Or FileSize(source$) < 0
MessageRequester("", "Исходный файл не существует, завершаем программу")
End ; если выбор отменён, то закрываем программу
EndIf
destination$ = GetGadgetText(#fieldPath2)
If Not Asc(destination$) Or FileSize(GetPathPart(destination$)) <> -2
MessageRequester("", "Не указан файл назначения или не существует каталог для файла, завершаем программу")
End ; если выбор отменён, то закрываем программу
EndIf
flag = 0
If GetGadgetState(#ch1)
flag + 1
EndIf
If GetGadgetState(#ch2)
flag + 2
EndIf
If GetGadgetState(#ch4)
flag + 4
EndIf
If GetGadgetState(#ch16)
flag + 16
EndIf
If GetGadgetState(#ch128)
flag + 128
EndIf
msg = 0
If GetGadgetState(#chmsg1)
msg + 1
EndIf
If GetGadgetState(#chmsg2)
msg + 2
EndIf
If GetGadgetState(#chmsg4)
msg + 4
EndIf
If GetGadgetState(#chOpen)
open = 1
Else
open = 0
EndIf
EndIf
Result\s = OpenFileToGadget(source$) ; вызов функции чтения файла с учётом кодировки.
;- Обработка
If msg & 2
StartTime = ElapsedMilliseconds()
EndIf
If flag & 1
cssCompression(@Result\s)
Result\s = ReplaceString(Result\s, Chr(1), "")
Result\s = ReplaceString(Result\s, ":0 0 0 0;", ":0;")
If flag & 16
RGBtoHEX(@Result)
EndIf
Else
If flag & 16
RGBtoHEX(@Result)
EndIf
cssTidy(@Result\s)
; Вычисляем длину данных css
; Len = 0
ForEach TextList()
Len + Len(TextList())
Next
; Экспортируем список в текстовые данные css
Result\s = Space(Len)
*Point = @Result\s
ForEach TextList()
CopyMemoryString(TextList(), @*Point)
Next
EndIf
If msg & 2
StartTime = ElapsedMilliseconds() - StartTime
EndIf
#File = 0
If CreateFile(#File, destination$, g_Format)
WriteStringFormat(#File, g_Format)
WriteString(#File, Result\s)
CloseFile(#File)
If open
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_Windows
RunProgram(destination$) ; открывает файл
CompilerCase #PB_OS_Linux
RunProgram("xdg-open", destination$, "") ; открывает файл
CompilerEndSelect
EndIf
EndIf
;- Message
; Вывод сообщений
If msg & 1 And Error
; реагируем на ошибку, когда открыта кавычка, но не найдена закрывающая кавычка, пришлось оборвать ожидание кавычки на конце строки
Message$ + "Количество ошибок: " + Str(Error) + #CRLF$
EndIf
If msg & 2
Message$ + "Выполнено за " + Str(StartTime) + " мсек" + #CRLF$
EndIf
If msg & 4
Message$ + source$ + #CRLF$ + destination$ + #CRLF$
EndIf
If Asc(Message$)
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_Windows
MessageRequester("info", Message$, #MB_SYSTEMMODAL)
CompilerCase #PB_OS_Linux
MessageRequester("info", Message$)
CompilerEndSelect
EndIf
;- END