From 354a1b50fca4ce5aaa6d5bff01a5442f12b20f03 Mon Sep 17 00:00:00 2001 From: Maurilio Longo Date: Sun, 30 Apr 2000 18:47:35 +0000 Subject: [PATCH] 20000430-20:35 GMT+2 Maurilio Longo --- harbour/ChangeLog | 29 ++- harbour/source/rtl/Makefile | 271 ++++++++++---------- harbour/source/rtl/dummy.prg | 6 +- harbour/source/rtl/teditor.prg | 437 +++++++++++++++++++++++++++++++++ 4 files changed, 596 insertions(+), 147 deletions(-) create mode 100644 harbour/source/rtl/teditor.prg diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 87e54d5def..c37680dfe4 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -1,20 +1,31 @@ +20000430-20:35 GMT+2 Maurilio Longo + + * source/rtl/teditor.prg + + Implements TEditor CLASS and exports MemoEdit function. VERY miminal + functionality / compatibility. Very little testing, but nonetheless fast + enough for medium sized text. + * source/rtl/Makefile + + added teditor.prg to list of needed files. + * source/rtl/dummy.prg + - removed MemoEdit() declaration + 20000430-17:45 GMT+1 Ryszard Glab *include/hbcomp.h *include/hbexprop.h *include/hbmacro.h *source/vm/macro.c - * removed redundancy in extern declarations - * removed unused bStackAffected parameter used for - strong typing + * removed redundancy in extern declarations + * removed unused bStackAffected parameter used for + strong typing 20000430-13:50 GMT+1 Ryszard Glab *source/compiler/harbour.c - *fixed possible memory reallocation error in hb_compNOOPadd() - + *fixed possible memory reallocation error in hb_compNOOPadd() + *source/compiler/hbpcode.c - *fixed pVar -> pSym + *fixed pVar -> pSym 20000430 04:10 GMT-3 Luiz Rafael Culik *contrib/libgt/doc/gendoc.bat @@ -38,7 +49,7 @@ * harbour/source/compiler/harbour.y ! Fixed hb_compExprCBVarAdd( $0, $1, $2 ) to hb_compExprCBVarAdd( $0, $1, hb_comp_cVarType ) and - hb_compExprCBVarAdd( $0, $3, $4 ) to hb_compExprCBVarAdd( $0, $3, hb_comp_cVarType ) so that + hb_compExprCBVarAdd( $0, $3, $4 ) to hb_compExprCBVarAdd( $0, $3, hb_comp_cVarType ) so that correct type is passed. + Added hb_comp_cVarType = ' ' to reset declared type after BlockVar[s] PRIVATE and PUBLIC. @@ -81,8 +92,8 @@ 20000427-20:40 GMT+1 Ryszard Glab *source/compiler/harbour.c - * changed hb_xgrab/hb_xrealloc to use sprintf in case - unsuccessfull allocation only + * changed hb_xgrab/hb_xrealloc to use sprintf in case + unsuccessfull allocation only 20000426 23:30 Luiz Rafael Culik !ChangeLog diff --git a/harbour/source/rtl/Makefile b/harbour/source/rtl/Makefile index 4333c97087..e8deed3c25 100644 --- a/harbour/source/rtl/Makefile +++ b/harbour/source/rtl/Makefile @@ -5,143 +5,144 @@ ROOT = ../../ C_SOURCES=\ - abs.c \ - accept.c \ - ampm.c \ - at.c \ - binnum.c \ - binnumx.c \ - box.c \ - chrasc.c \ - colorind.c \ - console.c \ - copyfile.c \ - datec.c \ - dates.c \ - dateshb.c \ - datesx.c \ - defpath.c \ - descend.c \ - dir.c \ - dirdrive.c \ - diskspac.c \ - do.c \ - empty.c \ - errorapi.c \ - eval.c \ - filesys.c \ - fkmax.c \ - fnsplit.c \ - fssize.c \ - fstemp.c \ - gete.c \ - gt.c \ - gtapi.c \ - gx.c \ - hardcr.c \ - inkey.c \ - is.c \ - isprint.c \ - langapi.c \ - left.c \ - len.c \ - lennum.c \ - math.c \ - maxrow.c \ - memofile.c \ - memoline.c \ - minmax.c \ - mlcount.c \ - mlpos.c \ - mod.c \ - mouseapi.c \ - mousex.c \ - mtran.c \ - natmsg.c \ - net.c \ - oemansi.c \ - oldbox.c \ - oldclear.c \ - pad.c \ - padc.c \ - padl.c \ - padr.c \ - philes.c \ - philes53.c \ - philesx.c \ - rat.c \ - replic.c \ - right.c \ - round.c \ - run.c \ - samples.c \ - saverest.c \ - scroll.c \ - seconds.c \ - set.c \ - setcolor.c \ - setcurs.c \ - setpos.c \ - setposbs.c \ - shadow.c \ - soundex.c \ - space.c \ - str.c \ - strcase.c \ - strings.c \ - strmatch.c \ - strtran.c \ - strzero.c \ - stuff.c \ - substr.c \ - tone.c \ - trace.c \ - transfrm.c \ - trim.c \ - type.c \ - val.c \ - valtostr.c \ - valtype.c \ - version.c \ - word.c \ - xhelp.c \ - xsavescr.c \ + abs.c \ + accept.c \ + ampm.c \ + at.c \ + binnum.c \ + binnumx.c \ + box.c \ + chrasc.c \ + colorind.c \ + console.c \ + copyfile.c \ + datec.c \ + dates.c \ + dateshb.c \ + datesx.c \ + defpath.c \ + descend.c \ + dir.c \ + dirdrive.c \ + diskspac.c \ + do.c \ + empty.c \ + errorapi.c \ + eval.c \ + filesys.c \ + fkmax.c \ + fnsplit.c \ + fssize.c \ + fstemp.c \ + gete.c \ + gt.c \ + gtapi.c \ + gx.c \ + hardcr.c \ + inkey.c \ + is.c \ + isprint.c \ + langapi.c \ + left.c \ + len.c \ + lennum.c \ + math.c \ + maxrow.c \ + memofile.c \ + memoline.c \ + minmax.c \ + mlcount.c \ + mlpos.c \ + mod.c \ + mouseapi.c \ + mousex.c \ + mtran.c \ + natmsg.c \ + net.c \ + oemansi.c \ + oldbox.c \ + oldclear.c \ + pad.c \ + padc.c \ + padl.c \ + padr.c \ + philes.c \ + philes53.c \ + philesx.c \ + rat.c \ + replic.c \ + right.c \ + round.c \ + run.c \ + samples.c \ + saverest.c \ + scroll.c \ + seconds.c \ + set.c \ + setcolor.c \ + setcurs.c \ + setpos.c \ + setposbs.c \ + shadow.c \ + soundex.c \ + space.c \ + str.c \ + strcase.c \ + strings.c \ + strmatch.c \ + strtran.c \ + strzero.c \ + stuff.c \ + substr.c \ + tone.c \ + trace.c \ + transfrm.c \ + trim.c \ + type.c \ + val.c \ + valtostr.c \ + valtype.c \ + version.c \ + word.c \ + xhelp.c \ + xsavescr.c \ PRG_SOURCES=\ - achoice.prg \ - adir.prg \ - alert.prg \ - browdb.prg \ - browdbx.prg \ - browse.prg \ - dbedit.prg \ - devoutp.prg \ - dircmd.prg \ - dummy.prg \ - errorsys.prg \ - fieldbl.prg \ - getlist.prg \ - getsys.prg \ - input.prg \ - memvarbl.prg \ - menuto.prg \ - objfunc.prg \ - readkey.prg \ - readvar.prg \ - setfunc.prg \ - setkey.prg \ - setta.prg \ - tclass.prg \ - tbcolumn.prg \ - tbrowse.prg \ - terror.prg \ - text.prg \ - tget.prg \ - tgetlist.prg \ - tlabel.prg \ - treport.prg \ - typefile.prg \ - wait.prg \ + achoice.prg \ + adir.prg \ + alert.prg \ + browdb.prg \ + browdbx.prg \ + browse.prg \ + dbedit.prg \ + devoutp.prg \ + dircmd.prg \ + dummy.prg \ + errorsys.prg \ + fieldbl.prg \ + getlist.prg \ + getsys.prg \ + input.prg \ + memvarbl.prg \ + menuto.prg \ + objfunc.prg \ + readkey.prg \ + readvar.prg \ + setfunc.prg \ + setkey.prg \ + setta.prg \ + tclass.prg \ + tbcolumn.prg \ + tbrowse.prg \ + teditor.prg \ + terror.prg \ + text.prg \ + tget.prg \ + tgetlist.prg \ + tlabel.prg \ + treport.prg \ + typefile.prg \ + wait.prg \ LIBNAME=rtl diff --git a/harbour/source/rtl/dummy.prg b/harbour/source/rtl/dummy.prg index c5de8e732d..a66d8e8225 100644 --- a/harbour/source/rtl/dummy.prg +++ b/harbour/source/rtl/dummy.prg @@ -42,10 +42,10 @@ FUNCTION ordCond() ; RETURN NIL FUNCTION ordDescend() ; RETURN .F. FUNCTION ordIsUnique() ; RETURN .F. FUNCTION ordKeyAdd() ; RETURN .F. -FUNCTION ordKeyCount() ; RETURN 0 +FUNCTION ordKeyCount() ; RETURN 0 FUNCTION ordKeyDel() ; RETURN .F. FUNCTION ordKeyGoto() ; RETURN .F. -FUNCTION ordKeyNo() ; RETURN 0 +FUNCTION ordKeyNo() ; RETURN 0 FUNCTION ordKeyVal() ; RETURN NIL FUNCTION ordSetRelation() ; RETURN NIL FUNCTION ordSkipUnique() ; RETURN .F. @@ -63,7 +63,7 @@ FUNCTION dbFieldInfo() ; RETURN NIL FUNCTION dbSetRelation() ; RETURN NIL FUNCTION dbClearRelation() ; RETURN NIL -FUNCTION MemoEdit( str ) ; RETURN str +//FUNCTION MemoEdit( str ) ; RETURN str FUNCTION MLCToPos() ; RETURN 0 FUNCTION MPosToLC() ; RETURN 0 diff --git a/harbour/source/rtl/teditor.prg b/harbour/source/rtl/teditor.prg new file mode 100644 index 0000000000..909cecfdb6 --- /dev/null +++ b/harbour/source/rtl/teditor.prg @@ -0,0 +1,437 @@ +/* + * Harbour Project source code: + * Implements a minimal editor class, could/should be used as a base for Memoedit() and, maybe, debugger. + * + * Copyright 2000 - Maurilio Longo + * www - http://www.harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version, with one exception: + * + * The exception is that if you link the Harbour Runtime Library (HRL) + * and/or the Harbour Virtual Machine (HVM) with other files to produce + * an executable, this does not by itself cause the resulting executable + * to be covered by the GNU General Public License. Your use of that + * executable is in no way restricted on account of linking the HRL + * and/or HVM code into it. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA (or visit + * their web site at http://www.gnu.org/). + * + */ + +/* TODO: Very minimal and little tested. To finish and refine */ + + +#include "hbclass.ch" +#include "error.ch" +#include "fileio.ch" +#include "inkey.ch" + +CLASS TEditor + + DATA cFile INIT "" // name of file being edited + + DATA aText INIT {} // array with lines of text being edited + DATA naTextLen INIT 0 // number of lines of text inside aText. Len function is not OK since deleting elements from + // array creates NIL elements at array end which kill every text funcion (like substr) used on + // array elements + + DATA nTop // boundaries of editor window, without box around + DATA nLeft + DATA nBottom + DATA nRight + + DATA nFirstCol INIT 1 // FirstCol/Row of current line visible inside editor window + DATA nFirstRow INIT 1 + DATA nRow INIT 1 // Cursor position inside aText (nRow) and inside current line of text (nCol) + DATA nCol INIT 1 + DATA nNumCols INIT 1 // How many columns / rows can be displayed inside editor window + DATA nNumRows INIT 1 + + DATA lInsert INIT .F. // Is editor in Insert mode or in Overstrike one? + DATA nTabWidth INIT 8 // Size of Tab chars + + METHOD New(cString, nTop, nLeft, nBottom, nRight) + METHOD RefreshWindow() + METHOD RefreshLine() + METHOD RefreshColumn() + METHOD MoveCursor(nKey) + METHOD InsertState(lInsState) // Changes lInsert value and insertion / overstrike mode of editor + METHOD Edit() + +ENDCLASS + +/* +METHOD New(cFile, nTop, nLeft, nBottom, nRight) CLASS TEditor + + LOCAL oFile := TFileRead():New(cFile) + + oFile:Open() + if oFile:Error() + Alert(oFile:ErrorMsg("FileRead: ")) + else + while oFile:MoreToRead() + AAdd(::aText, oFile:ReadLine()) + end while + oFile:Close() + + ::cFile := cFile + ::naTextLen := Len(::aText) + + // editor window boundaries + ::nTop := nTop + ::nLeft := nLeft + ::nBottom := nBottom + ::nRight := nRight + + // How many cols and rows are available + ::nNumCols := nRight - nLeft + 1 + ::nNumRows := nBottom - nTop + 1 + + // Empty area of screen which will hold editor window + Scroll(nTop, nLeft, nBottom, nRight) + + // Set cursor upper left corner + SetPos(::nTop, ::nLeft) + endif + +return Self +*/ + + +STATIC function Text2Array(cString) + + LOCAL cLine, i, nLastEOL, aArray + + nLastEOL := 1 + aArray := {} + + while nLastEOL > 0 + cLine := Left(cString, (nLastEol := at(HB_OSNewLine(), cString)) - 1) + cLine := StrTran(cLine, HB_OSNewLine(), "") + if nLastEOL > 0 + AAdd(aArray, cLine) + nLastEOL += Len(HB_OSNewLine()) + cString := SubStr(cString, nLastEOL) + endif + enddo + +return aArray + + +METHOD New(cString, nTop, nLeft, nBottom, nRight) CLASS TEditor + + ::aText := Text2Array(cString) + ::naTextLen := Len(::aText) + + // editor window boundaries + ::nTop := nTop + ::nLeft := nLeft + ::nBottom := nBottom + ::nRight := nRight + + // How many cols and rows are available + ::nNumCols := nRight - nLeft + 1 + ::nNumRows := nBottom - nTop + 1 + + // Empty area of screen which will hold editor window + Scroll(nTop, nLeft, nBottom, nRight) + + // Set cursor upper left corner + SetPos(::nTop, ::nLeft) + +return Self + + +// Redraws a screenfull of text +METHOD RefreshWindow() CLASS TEditor + + LOCAL i, nOCol, nORow + + nOCol := Col() + nORow := Row() + + for i := 0 to Min(::nNumRows - 1, ::naTextLen - 1) + DispOutAt(::nTop + i, ::nLeft, PadR(SubStr(::aText[::nFirstRow + i], ::nFirstCol, ::nNumCols), ::nNumCols, " ")) + next + + // Clear rest of editor window (needed when deleting lines of text) + if ::naTextLen < ::nNumRows + Scroll(::nTop + ::naTextLen, ::nLeft, ::nBottom, ::nRight) + endif + + SetPos(nORow, nOCol) + +return Self + + +// Redraws current screen line +METHOD RefreshLine() CLASS TEditor + + LOCAL nOCol, nORow + + nOCol := Col() + nORow := Row() + + DispOutAt(Row(), ::nLeft, PadR(SubStr(::aText[::nRow], ::nFirstCol, ::nNumCols), ::nNumCols, " ")) + + SetPos(nORow, nOCol) + +return Self + + +// Refreshes only one screen column of text (for Left() and Right() movements) +METHOD RefreshColumn() CLASS TEditor + + LOCAL i, nOCol, nORow + + nOCol := Col() + nORow := Row() + + for i := 0 to Min(::nNumRows - 1, ::naTextLen - 1) + DispOutAt(::nTop + i, nOCol, SubStr(::aText[::nFirstRow + i], ::nCol, 1)) + next + + SetPos(nORow, nOCol) + +return Self + + +// Handles cursor movements inside text array +METHOD MoveCursor(nKey) CLASS TEditor + + LOCAL lMoveKey := .T. + + do case + case (nKey == K_DOWN) + if Row() == ::nBottom + if ::nRow < ::naTextLen + Scroll(::nTop, ::nLeft, ::nBottom, ::nRight, 1) + ::nFirstRow++ + ::nRow++ + ::RefreshLine() + endif + else + if ::nRow < ::naTextLen + ::nRow++ + SetPos(Row() + 1, Col()) + endif + endif + + case (nKey == K_PGDN) + if ::nRow + ::nNumRows < ::naTextLen + ::nRow += ::nNumRows + ::nFirstRow += ::nNumRows + if ::nFirstRow + ::nNumRows > ::naTextLen + ::nFirstRow -= ((::nFirstRow + ::nNumRows) - ::naTextLen) + 1 + endif + else + ::nFirstRow := Max(::naTextLen - ::nNumRows + 1, 1) + ::nRow := ::naTextLen + SetPos(Min(::nTop + ::naTextLen - 1, ::nBottom), Col()) + endif + ::RefreshWindow() + + case (nKey == K_UP) + if Row() == ::nTop + if ::nRow > 1 + Scroll(::nTop, ::nLeft, ::nBottom, ::nRight, -1) + ::nFirstRow-- + ::nRow-- + ::RefreshLine() + endif + else + ::nRow-- + SetPos(Row() - 1, Col()) + endif + + case (nKey == K_PGUP) + if (::nRow - ::nNumRows) > 1 + ::nRow -= ::nNumRows + ::nFirstRow -= ::nNumRows + if ::nFirstRow < 1 + ::nFirstRow := 1 + endif + else + ::nFirstRow := 1 + ::nRow := 1 + SetPos(::nTop, Col()) + endif + ::RefreshWindow() + + case (nKey == K_RIGHT) + if Col() == ::nRight + // can go (<=) past end of line + if ::nCol <= Len(::aText[::nRow]) + Scroll(::nTop, ::nLeft, ::nBottom, ::nRight,, 1) + ::nFirstCol++ + ::nCol++ + ::RefreshColumn() + endif + else + ::nCol++ + SetPos(Row(), Col() + 1) + endif + + case (nKey == K_LEFT) + if Col() == ::nLeft + if ::nCol > 1 + Scroll(::nTop, ::nLeft, ::nBottom, ::nRight,, -1) + ::nFirstCol-- + ::nCol-- + ::RefreshColumn() + endif + else + ::nCol-- + SetPos(Row(), Col() - 1) + endif + + case (nKey == K_HOME) + ::nCol := 1 + ::nFirstCol := 1 + SetPos(Row(), ::nLeft) + ::RefreshWindow() + + case (nKey == K_END) + // Empty lines have 0 len + ::nCol := Max(Len(::aText[::nRow]), 1) + ::nFirstCol := Max(::nCol - ::nNumCols + 1, 1) + SetPos(Row(), Min(::nLeft + ::nCol - 1, ::nRight)) + ::RefreshWindow() + + otherwise + lMoveKey := .F. + + endcase + +return lMoveKey + + +// Changes lInsert value and insertion / overstrike mode of editor +METHOD InsertState(lInsState) CLASS TEditor + + ::lInsert := lInsState + +return Self + + +// Edits text +METHOD Edit() CLASS TEditor + + LOCAL i, nKey + + while .T. + + nKey := InKey(0) + do case + case (nKey >= 32 .AND. nKey < 256) + // insert char if in insert mode or at end of current line + if ::lInsert .OR. (::nCol == Len(::aText[::nRow])) + ::aText[::nRow] := Stuff(::aText[::nRow], ::nCol, 0, Chr(nKey)) + else + ::aText[::nRow] := Stuff(::aText[::nRow], ::nCol, 1, Chr(nKey)) + endif + ::MoveCursor(K_RIGHT) + ::RefreshLine() + + case (nKey == K_RETURN) + if ::lInsert .OR. ::nRow == ::naTextLen + AAdd(::aText, "") + if ::nRow < ::naTextLen + AIns(::aText, ::nRow + 1) + if Len(::aText[::nRow]) > 0 + // Split current line at cursor position + ::aText[::nRow + 1] := Right(::aText[::nRow], Len(::aText[::nRow]) - ::nCol + 1) + ::aText[::nRow] := Left(::aText[::nRow], ::nCol - 1) + else + ::aText[::nRow + 1] := "" + endif + endif + ::naTextLen++ + endif + ::MoveCursor(K_DOWN) + ::MoveCursor(K_HOME) + + case (nKey == K_INS) + ::InsertState(!::lInsert) + + case (nKey == K_DEL) + ::aText[::nRow] := Stuff(::aText[::nRow], ::nCol, 1, "") + ::RefreshLine() + + case (nKey == K_TAB) + // insert char if in insert mode or at end of current line + if ::lInsert .OR. (::nCol == Len(::aText[::nRow])) + ::aText[::nRow] := Stuff(::aText[::nRow], ::nCol, 0, Space(::nTabWidth)) + endif + for i := 1 to ::nTabWidth + ::MoveCursor(K_RIGHT) + next + ::RefreshLine() + + case (nKey == K_BS) + // delete previous character + ::aText[::nRow] := Stuff(::aText[::nRow], --::nCol, 1, "") + // correct column position for next call to MoveCursor() + ::nCol++ + ::MoveCursor(K_LEFT) + ::RefreshLine() + + case (nKey == K_CTRL_Y) + if ::naTextLen > 1 + // delete current line of text + ADel(::aText, ::nRow) + // Last element of array would be NIL, I need to transform it to an empy string because other methods + // expect every element to be a string + ::aText[::naTextLen] := "" + ::naTextLen-- + // if we now have less than a screen full of text, adjust nFirstRow position + if ::nFirstRow + ::nNumRows > ::naTextLen + ::nFirstRow := Max(::nFirstRow--, 1) + // if we have less lines of text than our current position on scree, up one line + if ::nRow > ::naTextLen + ::nRow := Max(::nRow--, 1) + SetPos(Max(Row() -1, ::nTop), Col()) + endif + endif + ::RefreshWindow() + else + ::aText[::nRow] := "" + ::RefreshLine() + endif + + case (::MoveCursor(nKey)) + // if it's a movement key ::MoveCursor() handles it + + case (nKey == K_ESC) + exit + + otherwise + // TODO: Here we should call an user defined function (to match memoedit() behaviour) + endcase + enddo + +return Self + + +/* TODO: MemoEdit() is not compatible with clipper one. Needs a lot more work to become */ +function MemoEdit(cString, nTop, nLeft, nBottom, nRight, lEditMode, cUserFunction, nLineLength, nTabSize, nTextBufferRow, nTextBufferColumn, nWindowRow, nWindowColumn) + + LOCAL oEd + + oEd := TEditor():New(cString, nTop, nLeft, nBottom, nRight) + oEd:RefreshWindow() + oEd:Edit() + +return cString +