diff --git a/src/main/ipc/index.ts b/src/main/ipc/index.ts index 7bb39bf..a1b84e1 100644 --- a/src/main/ipc/index.ts +++ b/src/main/ipc/index.ts @@ -389,9 +389,12 @@ export function registerIpcHandlers(): void { const phpDir = path.join(configService.getBasePath(), 'bin', `php-${version}`) const iniPath = path.join(phpDir, 'php.ini') if (fs.existsSync(iniPath)) { - return fs.readFileSync(iniPath, 'utf8') + return { + content: fs.readFileSync(iniPath, 'utf8'), + path: iniPath + } } - return '' + return { content: '', path: iniPath } }) ipcMain.handle('php:config:save', async (_event, { version, content }) => { diff --git a/src/renderer/src/components/PhpExtensionManager.tsx b/src/renderer/src/components/PhpExtensionManager.tsx index 399be16..a77fda1 100644 --- a/src/renderer/src/components/PhpExtensionManager.tsx +++ b/src/renderer/src/components/PhpExtensionManager.tsx @@ -19,6 +19,7 @@ import { } from '@mui/material' import { Search as SearchIcon, Close as CloseIcon, Refresh as RefreshIcon, EditNote as RawIcon, Save as SaveIcon } from '@mui/icons-material' import Swal from 'sweetalert2' +import PhpIniCodeEditor from './PhpIniCodeEditor' interface PhpExtension { name: string @@ -40,6 +41,8 @@ const PhpExtensionManager: React.FC = ({ open, onClose const [rawConfig, setRawConfig] = useState('') const [isRawEditorOpen, setIsRawEditorOpen] = useState(false) const [isSavingRaw, setIsSavingRaw] = useState(false) + const [configPath, setConfigPath] = useState('') + const [rawSearchTerm, setRawSearchTerm] = useState('') const fetchExtensions = async () => { if (!phpVersion) return @@ -58,7 +61,8 @@ const PhpExtensionManager: React.FC = ({ open, onClose if (!phpVersion) return try { const data = await window.api.invoke('php:config:get', phpVersion) - setRawConfig(data) + setRawConfig(data.content) + setConfigPath(data.path) setIsRawEditorOpen(true) } catch (error) { console.error('Failed to fetch raw config:', error) @@ -259,30 +263,53 @@ const PhpExtensionManager: React.FC = ({ open, onClose } }} > - - php.ini Düzenle ({phpVersion}) - setIsRawEditorOpen(false)} sx={{ color: 'rgba(255,255,255,0.5)' }}> - - - - - setRawConfig(e.target.value)} - variant="filled" - InputProps={{ - sx: { - fontFamily: 'monospace', - fontSize: '0.85rem', - color: '#d4d4d4', - bgcolor: '#1e1e1e', - '& textarea': { p: 2 } - }, - disableUnderline: true + + + php.ini Düzenle ({phpVersion}) + setIsRawEditorOpen(false)} sx={{ color: 'rgba(255,255,255,0.5)' }}> + + + + window.api.invoke('shell:open-path', configPath)} + title="Dosyayı sistemde aç" + > + {configPath} + + + + setRawSearchTerm(e.target.value)} + InputProps={{ + startAdornment: ( + + + + ), + sx: { + color: '#fff', + bgcolor: 'rgba(255,255,255,0.05)', + '& fieldset': { borderColor: 'rgba(255,255,255,0.1)' } + } + }} + /> + + + diff --git a/src/renderer/src/components/PhpIniCodeEditor.tsx b/src/renderer/src/components/PhpIniCodeEditor.tsx new file mode 100644 index 0000000..8ca776f --- /dev/null +++ b/src/renderer/src/components/PhpIniCodeEditor.tsx @@ -0,0 +1,103 @@ +import React from 'react' +import Editor from 'react-simple-code-editor' +import Prism from 'prismjs' +import 'prismjs/components/prism-ini' +import 'prismjs/themes/prism-tomorrow.css' + +interface PhpIniCodeEditorProps { + value: string + onChange: (value: string) => void + searchTerm?: string +} + +const PhpIniCodeEditor: React.FC = ({ value, onChange, searchTerm }) => { + const editorRef = React.useRef(null) + + const highlightWithSearch = (code: string) => { + // 1. Get Prism highlighted HTML + let highlighted = Prism.highlight(code, Prism.languages.ini, 'ini') + + // 2. If search term exists, wrap it in + // Use a regex that avoids matching inside existing HTML tags + if (searchTerm && searchTerm.trim().length > 1) { + const escapedSearch = searchTerm.trim().replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + // This regex matches the search term only if it's not inside a tag (negative lookahead for > before <) + const regex = new RegExp(`(${escapedSearch})(?![^<]*>)`, 'gi') + highlighted = highlighted.replace(regex, '$1') + } + + return highlighted + } + + // Scroll to first match + React.useEffect(() => { + if (searchTerm && searchTerm.trim().length > 1 && editorRef.current) { + const index = value.toLowerCase().indexOf(searchTerm.toLowerCase().trim()) + if (index !== -1) { + const container = editorRef.current + const linesBefore = value.substring(0, index).split('\n').length + const lineHeight = 21 // Approx for 14px font + // Scroll the container, not the textarea + container.scrollTop = (linesBefore - 3) * lineHeight + } + } + }, [searchTerm]) + + return ( +
+ onChange(code)} + highlight={highlightWithSearch} + padding={15} + style={{ + fontFamily: '"Fira code", "Fira Mono", monospace', + fontSize: 14, + minHeight: '100%', + outline: 'none' + }} + textareaClassName="ini-editor-textarea" + preClassName="ini-editor-pre" + /> + +
+ ) +} + +export default PhpIniCodeEditor