@@ -2,30 +2,45 @@ package config_editor
22
33import (
44 "log"
5+ "strings"
56
67 "gopkg.in/ini.v1"
78)
89
910type GameConfig struct {
10- file * ini.File
11- path string
11+ file * ini.File
12+ path string
13+ keyMap map [string ]map [string ]string // section -> key -> originalKey
1214}
1315
1416// Загрузка INI с сохранением структуры и комментариев
1517func (c * GameConfig ) Load (path string ) error {
18+ // Устанавливаем имя дефолтной секции в пустую строку ПЕРЕД загрузкой,
19+ // чтобы ключи без секции попадали в секцию "" (а не "DEFAULT").
20+ // При сохранении, если имя секции совпадает с DefaultSection, заголовок не пишется.
21+ ini .DefaultSection = ""
22+
1623 cfg , err := ini .LoadSources (ini.LoadOptions {
1724 PreserveSurroundedQuote : true , // не трогать кавычки, если появятся
1825 SpaceBeforeInlineComment : true , // сохранить inline-комментарии
1926 AllowBooleanKeys : true ,
20- // Insensitive: true,
27+ // Insensitive: true, // Мы реализуем свою нечувствительность
2128 }, path )
2229 if err != nil {
2330 return err
2431 }
2532 c .file = cfg
2633 c .path = path
34+ c .keyMap = make (map [string ]map [string ]string )
2735
28- ini .DefaultSection = ""
36+ // Строим карту ключей
37+ for _ , section := range cfg .Sections () {
38+ secNameLower := strings .ToLower (section .Name ())
39+ c .keyMap [secNameLower ] = make (map [string ]string )
40+ for _ , key := range section .Keys () {
41+ c .keyMap [secNameLower ][strings .ToLower (key .Name ())] = key .Name ()
42+ }
43+ }
2944
3045 return nil
3146}
@@ -36,25 +51,103 @@ func (c *GameConfig) Get(section, key string) string {
3651 return ""
3752 }
3853
54+ // 1. Пытаемся найти точное совпадение
3955 sec , err := c .file .GetSection (section )
40- if err != nil {
56+ if err == nil && sec .HasKey (key ) {
57+ return sec .Key (key ).String ()
58+ }
59+
60+ // 2. Если не нашли, ищем через карту (case-insensitive)
61+ secNameLower := strings .ToLower (section )
62+ keyLower := strings .ToLower (key )
63+
64+ // Ищем реальное имя секции
65+ var realSectionName string
66+
67+ // Сначала проверяем, может секция с таким именем есть (но ключ не нашли выше)
68+ if s , err := c .file .GetSection (section ); err == nil {
69+ realSectionName = s .Name ()
70+ } else {
71+ // Если нет, ищем перебором (так как keyMap хранит только lower case ключи секций)
72+ for _ , s := range c .file .Sections () {
73+ if strings .EqualFold (s .Name (), section ) {
74+ realSectionName = s .Name ()
75+ break
76+ }
77+ }
78+ }
79+
80+ if realSectionName == "" {
4181 return "not found section"
4282 }
4383
44- k := sec .Key (key )
45- if k == nil {
46- return "not found key"
84+ // Теперь ищем ключ в этой секции
85+ sec , _ = c .file .GetSection (realSectionName )
86+
87+ // Проверяем маппинг ключа
88+ if mapping , ok := c .keyMap [secNameLower ]; ok {
89+ if realKey , ok := mapping [keyLower ]; ok {
90+ return sec .Key (realKey ).String ()
91+ }
92+ }
93+
94+ // Если в мапе нет, но вдруг он есть в файле (добавили динамически?)
95+ if sec .HasKey (key ) {
96+ return sec .Key (key ).String ()
4797 }
4898
49- return k . String () // если значения нет → вернётся " "
99+ return "not found key "
50100}
51101
52102// Обновить значение
53103func (c * GameConfig ) Set (section , key , value string ) {
54104 if c .file == nil {
55105 return
56106 }
57- c .file .Section (section ).Key (key ).SetValue (value )
107+
108+ secNameLower := strings .ToLower (section )
109+ keyLower := strings .ToLower (key )
110+
111+ // 1. Определяем реальное имя секции
112+ var realSection * ini.Section
113+ if s , err := c .file .GetSection (section ); err == nil {
114+ realSection = s
115+ } else {
116+ for _ , s := range c .file .Sections () {
117+ if strings .EqualFold (s .Name (), section ) {
118+ realSection = s
119+ break
120+ }
121+ }
122+ }
123+
124+ // Если секции нет - создаем (с тем именем, которое передали)
125+ if realSection == nil {
126+ realSection , _ = c .file .NewSection (section )
127+ // Обновляем мапу
128+ if c .keyMap == nil {
129+ c .keyMap = make (map [string ]map [string ]string )
130+ }
131+ c .keyMap [secNameLower ] = make (map [string ]string )
132+ }
133+
134+ // 2. Определяем реальное имя ключа
135+ realKeyName := key // По умолчанию - как передали
136+
137+ if mapping , ok := c .keyMap [secNameLower ]; ok {
138+ if existingKey , ok := mapping [keyLower ]; ok {
139+ realKeyName = existingKey
140+ }
141+ }
142+
143+ // 3. Устанавливаем значение
144+ realSection .Key (realKeyName ).SetValue (value )
145+
146+ // 4. Обновляем мапу (на случай если это новый ключ)
147+ if c .keyMap [secNameLower ] == nil {
148+ c .keyMap [secNameLower ] = make (map [string ]string )
149+ }
150+ c.keyMap [secNameLower ][keyLower ] = realKeyName
58151}
59152
60153// Сохранить обратно в файл
0 commit comments