Subversion Repositories fastphp

Compare Revisions

Regard whitespace Rev 91 → Rev 90

/trunk/Private/Wishlist.md
27,7 → 27,3
7. More intelligent find of the correct method/function/symbol when you press F1
 
8. When dark theme is enabled, the left top pixel cannot be used to open the window menu (close by double click). This is extremely annoying if you are used to close maximized windows this way.
 
9. Console output (lower part of the screen): Button to stop the execution, and show flushed output in realtime
 
10. ANSI/UTF8 Saving and Auto Detect loading
/trunk/EditorMain.dfm
45,7 → 45,6
Width = 1112
Height = 245
Align = alClient
Color = clCream
Font.Charset = ANSI_CHARSET
Font.Color = clWindowText
Font.Height = -11
62,6 → 61,10
object HtmlTabSheet: TTabSheet
Caption = 'HTML'
ImageIndex = 1
ExplicitLeft = 0
ExplicitTop = 0
ExplicitWidth = 0
ExplicitHeight = 0
object WebBrowser1: TWebBrowser
Left = 0
Top = 0
107,7 → 110,6
Width = 836
Height = 321
Align = alClient
Color = clCream
ActiveLineColor = 14680010
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
179,7 → 181,6
Width = 273
Height = 321
Align = alLeft
Color = clCream
Images = ImageList1
Indent = 19
ReadOnly = True
190,6 → 191,10
object HelpTabsheet: TTabSheet
Caption = 'Help'
ImageIndex = 1
ExplicitLeft = 0
ExplicitTop = 0
ExplicitWidth = 0
ExplicitHeight = 0
object WebBrowser2: TWebBrowser
Left = 0
Top = 0
678,8 → 683,6
Width = 75
Height = 35
Action = ActionSpaceToTab
ParentShowHint = False
ShowHint = True
TabOrder = 9
end
object btnLint: TButton
688,8 → 691,6
Width = 75
Height = 35
Action = ActionLint
ParentShowHint = False
ShowHint = True
TabOrder = 10
end
end
743,12 → 744,12
Left = 132
Top = 252
object ActionFind: TAction
Caption = 'Find...'
Caption = 'Find'
ShortCut = 16454
OnExecute = ActionFindExecute
end
object ActionReplace: TAction
Caption = 'Replace...'
Caption = 'Replace'
ShortCut = 16456
OnExecute = ActionReplaceExecute
end
763,7 → 764,7
OnExecute = ActionFindPrevExecute
end
object ActionGoto: TAction
Caption = 'Goto line...'
Caption = 'Goto line'
ShortCut = 16455
OnExecute = ActionGotoExecute
end
772,12 → 773,6
ShortCut = 16467
OnExecute = ActionSaveExecute
end
object ActionSaveAs: TAction
Caption = 'Save as...'
Hint = 'Save as a new file'
ShortCut = 24659
OnExecute = ActionSaveAsExecute
end
object ActionHelp: TAction
Caption = 'Help'
ShortCut = 112
793,15 → 788,6
ShortCut = 8312
OnExecute = ActionRunConsoleExecute
end
object ActionGoToPHPDir: TAction
Caption = 'Go to PHP dir'
OnExecute = ActionGoToPHPDirExecute
end
object ActionPHPInteractiveShell: TAction
Caption = 'PHP Interactive Shell'
Hint = 'Opens the PHP Interactive Shell'
OnExecute = ActionPHPInteractiveShellExecute
end
object ActionESC: TAction
Caption = 'Esc'
ShortCut = 27
815,13 → 801,10
object ActionSpaceToTab: TAction
Caption = 'SpaceToTab'
Hint = 'Converts leading spaces to tabs'
ShortCut = 24660
OnExecute = ActionSpaceToTabExecute
end
object ActionLint: TAction
Caption = 'Lint'
Hint = 'Run PHP Lint (php -l) to check for syntax errors'
ShortCut = 24652
OnExecute = ActionLintExecute
end
end
850,10 → 833,12
Action = ActionRunConsole
end
object GotoPHPdir1: TMenuItem
Action = ActionGoToPHPDir
Caption = 'Go to PHP dir'
OnClick = GotoPHPdir1Click
end
object PHPShell1: TMenuItem
Action = ActionPHPInteractiveShell
Caption = 'PHP Interactive Shell'
OnClick = PHPShell1Click
end
end
object SavePopup: TPopupMenu
860,11 → 845,13
Left = 196
Top = 28
object Save1: TMenuItem
Action = ActionSave
Caption = 'Save'
Default = True
OnClick = Save1Click
end
object Saveas1: TMenuItem
Action = ActionSaveAs
Caption = 'Save as...'
OnClick = Saveas1Click
end
end
object SaveDialog1: TSaveDialog
/trunk/EditorMain.pas
11,7 → 11,8
You can obtain SynEdit via Embarcadero GetIt
*)
 
// TODO: "crHourGlass" does not work if F9 is pressed!
// TODO: "DragAcceptFiles" does not work with Delphi Dark Design Template !!!
 
// TODO: if a scrapfile is already open, create a new scrap file (scrap2.php)
// TODO: localize
// TODO: wieso geht copy paste im twebbrowser nicht???
21,19 → 22,6
// TODO: "jump to next/prev todo" buttons/shortcuts
// TODO: "increase/decrease indent" buttons/shortcuts
 
// In regards Unicode:
// - Solve compiler warnings
// - If you place Unicode symbols in a ANSI file, they will be replaced during saving
// by "?" without asking the user if the code should be converted to Unicode!
// - FastPHP can only read a UTF-8 file correctly if it has a BOM
// However, the PSR-1 standard requires that files have UTF-8 without BOM!
// So we need auto-detect (since many people are working with ANSI!)
// - When a file is correctly loaded with UTF-8/BOM,
// the run output (Plaintext and HTML) will show UTF-8 instead of Unicode
// (that COULD be intended since the Windows CMD is not Unicode ready?)
// But HTML is also shown as UTF-8 even though I have added <meta charset="UTF-8"> ?!
// - Is it possible that UTF8 BOM automatically gets removed by FastPHP, generating pure ANSI?
 
// Small things:
// - The scroll bars of SynEdit are not affected by the dark theme
 
42,12 → 30,12
// - verschiedene php versionen?
// - webbrowser1 nur laden, wenn man den tab anwählt?
// - doppelklick auf tab soll diesen schließen
// - Onlinehelp (www) aufrufen oder CHM datei
// - Onlinehelp (www) aufrufen
// - Let all colors be adjustable
// - code in bildschirmmitte (horizontal)?
// - search in files of a directory
// - Files in multiple tabs?
// - Configurable tabulator display-width
// - multi tab?
// - DDE (drag n drop)
 
interface
 
127,9 → 115,6
FileModTimer: TTimer;
GotoPHPdir1: TMenuItem;
PHPShell1: TMenuItem;
ActionSaveAs: TAction;
ActionGoToPHPDir: TAction;
ActionPHPInteractiveShell: TAction;
procedure Run(Sender: TObject);
procedure RunConsole(Sender: TObject);
procedure FormShow(Sender: TObject);
181,6 → 166,8
procedure ActionLintExecute(Sender: TObject);
procedure ActionRunConsoleExecute(Sender: TObject);
procedure SynEdit1Change(Sender: TObject);
procedure Saveas1Click(Sender: TObject);
procedure Save1Click(Sender: TObject);
procedure BtnSpecialCharsClick(Sender: TObject);
procedure WebBrowser1WindowClosing(ASender: TObject;
IsChildWindow: WordBool; var Cancel: WordBool);
187,11 → 174,10
procedure BtnLightClick(Sender: TObject);
procedure StartUpTimerTimer(Sender: TObject);
procedure FileModTimerTimer(Sender: TObject);
procedure GotoPHPdir1Click(Sender: TObject);
procedure PHPShell1Click(Sender: TObject);
procedure SynEdit1DropFiles(Sender: TObject; X, Y: Integer;
AFiles: TStrings);
procedure ActionSaveAsExecute(Sender: TObject);
procedure ActionGoToPHPDirExecute(Sender: TObject);
procedure ActionPHPInteractiveShellExecute(Sender: TObject);
private
hMutex: THandle;
CurSearchTerm: string;
201,8 → 187,6
gOnlineHelpWord: string;
{$ENDIF}
FileModLast: TDateTime;
FormShowRanOnce: boolean;
BrowserLoadedOnce: boolean;
procedure Help;
function InputRequestCallback(var data: AnsiString): boolean;
function OutputNotifyCallback(const data: AnsiString): boolean;
265,15 → 249,12
var
val: string;
lineno: integer;
resourcestring
SGoTo = 'Go to';
SLineNumber = 'Line number:';
begin
// TODO: VK_LMENU does not work! only works with AltGr but not Alt
// http://stackoverflow.com/questions/16828250/delphi-xe2-how-to-prevent-the-alt-key-stealing-focus ?
 
if not InputQuery(SGoTo, SLineNumber, val) or
not TryStrToInt(val, lineno) then
InputQuery('Go to', 'Line number:', val);
if not TryStrToInt(val, lineno) then
begin
if SynEdit1.CanFocus then SynEdit1.SetFocus;
exit;
281,15 → 262,6
GotoLineNo(lineno);
end;
 
procedure TForm1.ActionGoToPHPDirExecute(Sender: TObject);
var
phpExe: string;
begin
phpExe := GetPHPExe;
if phpExe <> '' then
ShellExecute(Handle, 'open', 'explorer.exe', PChar(ExtractFilePath(phpExe)), '', SW_NORMAL);
end;
 
procedure TForm1.ActionHelpExecute(Sender: TObject);
begin
Help;
313,15 → 285,6
end;
end;
 
procedure TForm1.ActionPHPInteractiveShellExecute(Sender: TObject);
var
phpExe: string;
begin
phpExe := GetPHPExe;
if phpExe <> '' then
ShellExecute(Handle, 'open', PChar(phpExe), '-a', PChar(ExtractFilePath(phpExe)), SW_NORMAL);
end;
 
procedure TForm1.ActionReplaceExecute(Sender: TObject);
begin
SrcRep.ReplaceExecute;
362,33 → 325,6
*)
end;
 
procedure TForm1.ActionSaveAsExecute(Sender: TObject);
var
hMutexNew: THandle;
resourcestring
SCannotSaveBecauseMutex = 'Cannot save because file "%s", because it is alrady open in another FastPHP window!';
begin
if SaveDialog1.Execute then
begin
{$REGION 'Switch mutex'}
hMutexNew := CreateMutex(nil, True, PChar('FastPHP'+md5(UpperCase(SaveDialog1.FileName))));
if GetLastError = ERROR_ALREADY_EXISTS then
begin
ShowMessageFmt(SCannotSaveBecauseMutex, [SaveDialog1.FileName]);
Close;
end;
 
if hMutex <> 0 then CloseHandle(hMutex); // Note: ReleaseMutex does not work as expected!
hMutex := hMutexNew;
{$ENDREGION}
 
FSaveAsFilename := SaveDialog1.FileName;
Caption := Copy(Caption, 1, Pos(' - ', Caption)-1) + ' - ' + FSaveAsFilename;
Application.Title := Format('%s - FastPHP', [ExtractFileName(FSaveAsFilename)]); // do not translate!
Button7.Click;
end;
end;
 
procedure TForm1.ActionSaveExecute(Sender: TObject);
begin
RightTrimAll;
471,8 → 407,6
ind: integer;
resourcestring
SNoLinesAvailable = 'No lines with spaces at the beginning available';
SSpacesToLabs = 'Spaces to tabs';
SIndent = 'Indent:';
begin
// TODO: if something is selected, only process the selected part
 
485,17 → 419,16
ind := GuessIndent(SynEdit1.Lines);
if ind <> -1 then val := IntToStr(ind);
 
if not InputQuery(SSpacesToLabs, SIndent, val) or
not TryStrToInt(Trim(val), ind) then
InputQuery('Spaces to tabs', 'Indent:', val); // TODO: handle CANCEL correctly...
if TryStrToInt(Trim(val), ind) then
begin
if SynEdit1.CanFocus then SynEdit1.SetFocus;
exit;
end;
 
if ind = 0 then exit;
SpaceToTab(SynEdit1.Lines, ind);
end;
 
if SynEdit1.CanFocus then SynEdit1.SetFocus;
end;
 
procedure TForm1.ActionESCExecute(Sender: TObject);
begin
if (HlpPrevPageIndex <> -1) and (PageControl2.ActivePage = HelpTabSheet) and
514,6 → 447,8
SrcRep.FindExecute;
end;
 
var
firstTimeBrowserLoad: boolean = true;
procedure TForm1.Run(Sender: TObject);
var
bakTS: TTabSheet;
522,7 → 457,7
begin
memo2.Lines.Text := '';
 
if not BrowserLoadedOnce then
if firstTimeBrowserLoad then
begin
bakTS := PageControl1.ActivePage;
try
531,12 → 466,12
finally
PageControl1.ActivePage := bakTS;
end;
BrowserLoadedOnce := true;
firstTimeBrowserLoad := false;
end
else
Webbrowser1.Clear;
 
Screen.Cursor := crHourGlass; // TODO: Doesn't work with F9
Screen.Cursor := crHourGlass;
Application.ProcessMessages;
 
try
586,12 → 521,10
FileName: string;
const
WARN_FILE_COUNT = 10;
resourcestring
SAreYouSure = 'Are you sure you want to open %d files?';
begin
if AFiles.Count > WARN_FILE_COUNT then
begin
if not MessageDlg(Format(SAreYouSure, [WARN_FILE_COUNT]), mtConfirmation, mbYesNoCancel, 0) <> mrYes then
if not MessageDlg(Format('Are you sure you want to open %d files?', [WARN_FILE_COUNT]), mtConfirmation, mbYesNoCancel, 0) <> mrYes then
exit;
end;
 
818,7 → 751,7
procedure TForm1.Theme_Dark;
begin
if IsThemeDark then exit;
TStyleManager.TrySetStyle('Windows10 SlateGray'); // do not translate
TStyleManager.TrySetStyle('Windows10 SlateGray');
Color := 1316887;
Font.Color := clCream;
//Memo2.Font.Color := clCream;
842,12 → 775,12
procedure TForm1.Theme_Light;
begin
if not IsThemeDark then exit;
TStyleManager.TrySetStyle('Windows'); // do not translate
TStyleManager.TrySetStyle('Windows');
Color := clBtnFace;
Font.Color := clWindowText;
//Memo2.Font.Color := clWindowText;
SynEdit1.ActiveLineColor := 14680010;
SynEdit1.Color := clCream;
SynEdit1.Color := clWindow;
SynEdit1.Font.Color := clWindowText;
SynEdit1.Gutter.Color := clBtnFace;
SynEdit1.Gutter.Font.Color := clWindowText;
906,9 → 839,9
procedure TForm1.WebBrowser1WindowClosing(ASender: TObject;
IsChildWindow: WordBool; var Cancel: WordBool);
resourcestring
SCloseRequest = 'A script has requested the window to be closed. The window of a standalone script would now close.';
LNG_CLOSE_REQUEST = 'A script has requested the window to be closed. The window of a standalone script would now close.';
begin
ShowMessage(SCloseRequest);
ShowMessage(LNG_CLOSE_REQUEST);
TWebBrowser(ASender).Clear;
Cancel := true;
end;
997,9 → 930,6
end;
 
procedure TForm1.FileModTimerTimer(Sender: TObject);
resourcestring
SChangeConflict = 'The file was changed in a different application BUT IT WAS ALSO MODIFIED HERE! Reload file AND LOSE CHANGES HERE?';
SChangeNotify = 'The file was changed in a different application! Reload file?';
begin
FileModTimer.Enabled := false;
if FileModLast <> FileAge(GetScrapFile) then
1007,7 → 937,7
FileModLast := FileAge(GetScrapFile);
if SynEdit1.Modified then
begin
if MessageDlg(SChangeConflict, mtWarning, mbYesNoCancel, 0) = mrYes then
if MessageDlg('The file was changed in a different application BUT IT WAS ALSO MODIFIED HERE! Reload file AND LOSE CHANGES HERE?', mtWarning, mbYesNoCancel, 0) = mrYes then
begin
SynEdit1.Lines.LoadFromFile(GetScrapFile);
end;
1014,7 → 944,7
end
else
begin
if MessageDlg(SChangeNotify, mtConfirmation, mbYesNoCancel, 0) = mrYes then
if MessageDlg('The file was changed in a different application! Reload file?', mtConfirmation, mbYesNoCancel, 0) = mrYes then
begin
SynEdit1.Lines.LoadFromFile(GetScrapFile);
end;
1032,14 → 962,12
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
var
r: integer;
resourcestring
SWantToSave = 'Do you want to save?';
begin
if SynEdit1.Modified then
begin
if (ParamStr(1) <> '') or (FSaveAsFilename <> '') then
begin
r := MessageDlg(SWantToSave, mtConfirmation, mbYesNoCancel, 0);
r := MessageDlg('Do you want to save?', mtConfirmation, mbYesNoCancel, 0);
if r = mrCancel then
begin
CanClose := false;
1068,7 → 996,7
CurSearchTerm := '';
sScrapFile := GetScrapFile;
Caption := Caption + ' - ' + sScrapFile;
Application.Title := Format('%s - FastPHP', [ExtractFileName(sScrapFile)]); // do not translate!
Application.Title := Format('%s - FastPHP', [ExtractFileName(sScrapFile)]);
SrcRep := TSynEditFindReplace.Create(self);
SrcRep.Editor := SynEdit1;
SynEdit1.Gutter.Gradient := HighColorWindows;
1101,13 → 1029,13
end;
end;
 
var
FormShowRanOnce: boolean;
procedure TForm1.FormShow(Sender: TObject);
var
ScrapFile: string;
tmpFontSize: integer;
opts: TSynEditorOptions;
resourcestring
SFileAlreadyOpen = 'File "%s" is alrady open!';
begin
if FormShowRanOnce then exit; // If the theme is changed from normal to dark, OnShow will be called another time
FormShowRanOnce := true;
1140,7 → 1068,7
if GetLastError = ERROR_ALREADY_EXISTS then
begin
// TODO: It would be great if the window of that FastPHP instance would switched to foreground
ShowMessageFmt(SFileAlreadyOpen, [ScrapFile]);
ShowMessageFmt('File "%s" is alrady open!', [ScrapFile]);
Close;
end;
 
1167,6 → 1095,36
StartupTimer.Enabled := true;
end;
 
procedure TForm1.Save1Click(Sender: TObject);
begin
Button7.Click;
end;
 
procedure TForm1.Saveas1Click(Sender: TObject);
var
hMutexNew: THandle;
begin
if SaveDialog1.Execute then
begin
{$REGION 'Switch mutex'}
hMutexNew := CreateMutex(nil, True, PChar('FastPHP'+md5(UpperCase(SaveDialog1.FileName))));
if GetLastError = ERROR_ALREADY_EXISTS then
begin
ShowMessageFmt('Cannot save because file "%s", because it is alrady open in another FastPHP window!', [SaveDialog1.FileName]);
Close;
end;
 
if hMutex <> 0 then CloseHandle(hMutex); // Note: ReleaseMutex does not work as expected!
hMutex := hMutexNew;
{$ENDREGION}
 
FSaveAsFilename := SaveDialog1.FileName;
Caption := Copy(Caption, 1, Pos(' - ', Caption)-1) + ' - ' + FSaveAsFilename;
Application.Title := Format('%s - FastPHP', [ExtractFileName(FSaveAsFilename)]);
Button7.Click;
end;
end;
 
procedure TForm1.SaveToFile(filename: string);
var
ss: TStringStream;
1280,9 → 1238,6
function TForm1.GetScrapFile: string;
var
tmpPath: string;
resourcestring
SFileDoesNotExistsCreate = 'File %s does not exist. Create it?';
SPathDoesNotExistTryAgain = 'Path does not exist! Please try again.';
begin
if FSaveAsFilename <> '' then
begin
1304,7 → 1259,7
 
if not FileExists(result) then
begin
case MessageDlg(Format(SFileDoesNotExistsCreate, [result]), mtConfirmation, mbYesNoCancel, 0) of
case MessageDlg(Format('File %s does not exist. Create it?', [result]), mtConfirmation, mbYesNoCancel, 0) of
mrYes:
try
SaveToFile(result);
1370,7 → 1325,7
 
if not DirectoryExists(ExtractFilePath(OpenDialog3.FileName)) then
begin
MessageDlg(SPathDoesNotExistTryAgain, mtWarning, [mbOk], 0);
MessageDlg('Path does not exist! Please try again.', mtWarning, [mbOk], 0);
end
else
begin
1405,10 → 1360,6
var
IndexFile, chmFile, w, OriginalWord, url: string;
internalHtmlFile: string;
resourcestring
SChmFileNotAValidPHPDocumentation = 'The CHM file is not a valid PHP documentation. Cannot use help.';
SUnknownErrorCannotUseHelp = 'Unknown error. Cannot use help.';
SNoHelpAvailable = 'No help for "%s" available';
begin
if not Assigned(ChmIndex) then
begin
1451,7 → 1402,7
try
if not ParseCHM(chmFile) then
begin
MessageDlg(SChmFileNotAValidPHPDocumentation, mtError, [mbOk], 0);
MessageDlg('The CHM file is not a valid PHP documentation. Cannot use help.', mtError, [mbOk], 0);
exit;
end;
finally
1461,7 → 1412,7
 
if not FileExists(IndexFile) then
begin
MessageDlg(SUnknownErrorCannotUseHelp, mtError, [mbOk], 0);
MessageDlg('Unknown error. Cannot use help.', mtError, [mbOk], 0);
exit;
end;
end;
1484,14 → 1435,14
w := LowerCase(w);
CurSearchTerm := w;
 
internalHtmlFile := ChmIndex.ReadString('function', CurSearchTerm, ''); // do not translate
internalHtmlFile := ChmIndex.ReadString('function', CurSearchTerm, '');
if internalHtmlFile = '' then
internalHtmlFile := ChmIndex.ReadString('_HelpWords_', CurSearchTerm, ''); // do not translate
internalHtmlFile := ChmIndex.ReadString('_HelpWords_', CurSearchTerm, '');
if internalHtmlFile = '' then
begin
HelpTabsheet.TabVisible := false;
HlpPrevPageIndex := -1;
ShowMessageFmt(SNoHelpAvailable, [Originalword]);
ShowMessageFmt('No help for "%s" available', [Originalword]);
Exit;
end;
 
1530,6 → 1481,15
if SynEdit1.CanFocus then SynEdit1.SetFocus;
end;
 
procedure TForm1.GotoPHPdir1Click(Sender: TObject);
var
phpExe: string;
begin
phpExe := GetPHPExe;
if phpExe <> '' then
ShellExecute(Handle, 'open', 'explorer.exe', PChar(ExtractFilePath(phpExe)), '', SW_NORMAL);
end;
 
procedure TForm1.PageControl2Changing(Sender: TObject;
var AllowChange: Boolean);
begin
1541,6 → 1501,15
AllowChange := true;
end;
 
procedure TForm1.PHPShell1Click(Sender: TObject);
var
phpExe: string;
begin
phpExe := GetPHPExe;
if phpExe <> '' then
ShellExecute(Handle, 'open', PChar(phpExe), '-a', PChar(ExtractFilePath(phpExe)), SW_NORMAL);
end;
 
procedure TForm1.Memo2DblClick(Sender: TObject);
var
line: string;
1569,7 → 1538,7
{$ENDREGION}
 
{$REGION 'Possibility 2: on line xx'}
_process(ExtractFileName(GetScrapFile) + ' on line '); // do not translate!
_process(ExtractFileName(GetScrapFile) + ' on line ');
{$ENDREGION}
end;
 
1624,7 → 1593,7
{$ENDREGION}
 
{$REGION 'Possibility 2: on line xx'}
_process(ExtractFileName(GetScrapFile) + ' on line '); // do not translate!
_process(ExtractFileName(GetScrapFile) + ' on line ');
{$ENDREGION}
 
result := cont;
1643,7 → 1612,7
 
function TForm1.OutputNotifyCallback(const data: AnsiString): boolean;
begin
result := TreeView1.FillWithFastPHPData(string(data));
result := TreeView1.FillWithFastPHPData(data);
end;
 
end.
/trunk/FastPHPBrowser.res
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/FastPHPEditor.res
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/README.md
1,4 → 1,4
# ViaThinkSoft FastPHP - Code Editor for PHP
# FastPHP
 
FastPHP is a simple, efficient, and comfortable editor/IDE for PHP. Besides syntax highlighting, a code explorer, and the execution of PHP scripts outside the browser, FastPHP offers other useful functionalities like PHP Lint, showing the PHP documentation by keystroke and automatic replacement of whitespaces into tabs.
 
5,48 → 5,13
Features:
- Loads very fast, similar to Notepad
- Syntax highlighting
- Code TreeView Explorer (written in PHP!), also shows TODO-Entries
- Code explorer
- Running PHP files without IDE and without browser
- Integrated PHP lint
- Conversation from whitespaces to tabs
- Integrated PHP help with the F1 key
- PHP files can be executed like HTA files via double-click
- Switch between Dark and Light theme
- Show/Hide formatting symbols
- Clicking on a PHP error will jump to the code line
- Automatically removes unnecessary spaces at end of lines and the end of file
- Integrate in Explorer as "Shell new" to quickly create new PHP files
- Dark and light design
- Show formatting symbols
 
** Download FastPHP for Windows here: https://www.viathinksoft.com/projects/fastphp **
 
## Shortcuts
 
- Ctrl+F: Find
- Ctrl+H: Replace
- F3: Find next
- Shift+F3: Find previous
- Ctrl+G: Go to line #
- Ctrl+S: Save
- Shift+Ctrl+S: Save as...
- Shift+Ctrl+L: Lint
- Shift+Ctrl+T: Space-to-Tab
- F1: Get help about selected word
- F9: Run script
- Shift+F9: Run script in console
- ESC: Close help page and go back to code
- Ctrl+O: Open file in new window
- Left mouse + scroll mouse: Scale font up/down
- Tab (on selection): Increase indent
- Shift + Tab (on selection): Decrease indent
- Right click on the "Run" button opens:
* Run
* Run in console
* Go to PHP dir (e.g. to edit php.ini)
* PHP Interactive Shell
- Right click on the "Save" button opens:
* Save
* Save as...
 
## Example screenshot
 
![Light theme](https://www.viathinksoft.com/screenshot/25/FastPHP.png)
**Download FastPHP for Windows here: https://www.viathinksoft.de/projects/fastphp**
/trunk/FastPHPUtils.pas
110,7 → 110,7
 
outFile := ChangeFileExt(chmFile, '.ini');
DeleteFile(outFile);
test := LoadFileToStr(chmFile); // TODO: RawByteString instead of AnsiString?
test := LoadFileToStr(chmFile);
if Pos('/php_manual_', test) = -1 then
begin
result := false;
213,7 → 213,7
var
cont: string;
begin
cont := LoadFileToStr(exeFile); // TODO: RawByteString instead of AnsiString?
cont := LoadFileToStr(exeFile);
result := (Pos('php://stdout', cont) >= 0) or
(Pos('PHP_SELF', cont) >= 0);
end;
/trunk/Functions.pas
9,7 → 9,7
type
TContentCallBack = procedure(Content: string) of object;
 
function GetDosOutput(CommandLine: string; Work: string = ''; ContentCallBack: TContentCallBack=nil): String;
function GetDosOutput(CommandLine: string; Work: string = ''; ContentCallBack: TContentCallBack=nil): string;
function StrIPos(const SubStr, S: string): Integer;
function LoadFileToStr(const FileName: TFileName): AnsiString;
function LastPos(const SubStr, S: string): integer;
31,7 → 31,7
ShlObj, // Needed for the CSIDL constants
IdGlobal, IdHash, IdHashMessageDigest; // used for MD5 calculation
 
function GetDosOutput(CommandLine: string; Work: string = ''; ContentCallBack: TContentCallBack=nil): String;
function GetDosOutput(CommandLine: string; Work: string = ''; ContentCallBack: TContentCallBack=nil): string;
var
SA: TSecurityAttributes;
SI: TStartupInfo;
75,8 → 75,8
if BytesRead > 0 then
begin
Buffer[BytesRead] := #0;
Result := Result + string(Buffer);
if Assigned(ContentCallBack) then ContentCallBack(string(Buffer));
Result := Result + Buffer;
if Assigned(ContentCallBack) then ContentCallBack(Buffer);
end;
until not WasOK or (BytesRead = 0);
WaitForSingleObject(PI.hProcess, INFINITE);
/trunk/RunPHP.pas
123,7 → 123,7
if BytesRead > 0 then
begin
Buffer[BytesRead] := #0;
Output := Output + string(Buffer);
Output := Output + Buffer;
if Pos(SIGNAL_END_OF_TRANSMISSION, Output) >= 1 then
begin
Output := StringReplace(Output, SIGNAL_END_OF_TRANSMISSION, '', []);
/trunk/BrowserMain.pas
15,7 → 15,6
TForm2 = class(TForm)
WebBrowser1: TWebBrowser;
Timer1: TTimer;
OpenDialog3: TOpenDialog;
procedure Timer1Timer(Sender: TObject);
procedure WebBrowser1BeforeNavigate2(ASender: TObject;
const pDisp: IDispatch; const URL, Flags, TargetFrameName, PostData,
130,11 → 129,6
var
phpScript: string;
sl: TStringList;
resourcestring
SRunningScriptPleaseWait = 'Running script... please wait...';
SPleaseEnterPHPScript = 'Please enter a PHP file to execute.';
SFileDoesNotExist = 'File %s does not exist.';
SFastPHP = 'ViaThinkSoft FastPHP';
begin
Timer1.Enabled := false;
phpScript := ParamStr(1);
142,22 → 136,18
// Remove Security
WebBrowser1.ServiceQuery := EmbeddedWBQueryService;
 
WebBrowser1.LoadHTML('<h1>'+SFastPHP+'</h1>'+SRunningScriptPleaseWait);
WebBrowser1.LoadHTML('<h1>FastPHP</h1>Running script... please wait...');
 
// TODO: nice HTML error/intro pages (as resource?)
if phpScript = '' then
begin
WebBrowser1.LoadHTML('<h1>'+SFastPHP+'</h1>'+SPleaseEnterPHPScript);
if not OpenDialog3.Execute then
begin
WebBrowser1.LoadHTML('<h1>FastPHP</h1>Please enter a PHP file to execute.');
Abort;
end;
phpScript := OpenDialog3.FileName;
end;
 
if not FileExists(phpScript) then
begin
WebBrowser1.LoadHTML(Format('<h1>'+SFastPHP+'</h1>'+SFileDoesNotExist, [phpScript]));
WebBrowser1.LoadHTML(Format('<h1>FastPHP</h1>File %s does not exist.', [phpScript]));
Abort;
end;
 
187,16 → 177,14
p: integer;
background: boolean;
ArgGet, ArgPost, ArgHeader: string;
resourcestring
SOnlyWorksInEditor = 'This action only works in FastPHP editor.';
begin
background := Pos('background|', URL) >= 1; // do not translate
background := Pos('background|', URL) >= 1;
 
{$REGION 'Line number references (PHP errors and warnings)'}
if Copy(URL, 1, length(FASTPHP_GOTO_URI_PREFIX)) = FASTPHP_GOTO_URI_PREFIX then
begin
// TODO: maybe we could even open that file in the editor!
ShowMessage(SOnlyWorksInEditor);
ShowMessage('This action only works in FastPHP editor.');
Cancel := true;
Exit;
end;
207,7 → 195,7
begin
myUrl := URL;
 
myurl := StringReplace(myurl, 'background|', '', []); // do not translate
myurl := StringReplace(myurl, 'background|', '', []);
 
p := Pos('?', myUrl);
if p >= 1 then
/trunk/BrowserMain.dfm
40,17 → 40,4
Left = 288
Top = 80
end
object OpenDialog3: TOpenDialog
DefaultExt = 'php'
FileName = 'scrap.php'
Filter =
'All PHP files (*.php*;*.phtml;*.inc;*.xphp)|*.php*;*.phtml;*.inc' +
';*.xphp|PHP files (*.php*;*.phtml)|*.php*;*.phtml|Include files ' +
'(*.inc)|*.inc|PHP source files (*.phps)|*.phps|Executable PHP fi' +
'le (*.xphp)|*.xphp|All files (*.*)|*.*'
Options = [ofHideReadOnly, ofPathMustExist, ofEnableSizing]
Title = 'Please select (or create) a scrap file'
Left = 352
Top = 88
end
end