diff --git a/.gitmodules b/.gitmodules index 589c87ae41..9bc0579f78 100644 --- a/.gitmodules +++ b/.gitmodules @@ -40,6 +40,9 @@ [submodule "vendor/grammars/FreeMarker.tmbundle"] path = vendor/grammars/FreeMarker.tmbundle url = https://github.com/freemarker/FreeMarker.tmbundle +[submodule "vendor/grammars/GeneroFgl.tmbundle"] + path = vendor/grammars/GeneroFgl.tmbundle + url = https://github.com/FourjsGenero/GeneroFgl.tmbundle.git [submodule "vendor/grammars/Handlebars"] path = vendor/grammars/Handlebars url = https://github.com/daaain/Handlebars @@ -479,9 +482,6 @@ [submodule "vendor/grammars/gemini-vscode"] path = vendor/grammars/gemini-vscode url = https://github.com/printfn/gemini-vscode.git -[submodule "vendor/grammars/genero.tmbundle"] - path = vendor/grammars/genero.tmbundle - url = https://github.com/alienriver49/genero.tmbundle [submodule "vendor/grammars/gettext.tmbundle"] path = vendor/grammars/gettext.tmbundle url = https://github.com/textmate/gettext.tmbundle diff --git a/grammars.yml b/grammars.yml index 381a8d172a..d6cdd59be8 100644 --- a/grammars.yml +++ b/grammars.yml @@ -32,6 +32,9 @@ vendor/grammars/Elm/Syntaxes: - text.html.mediawiki.elm-documentation vendor/grammars/FreeMarker.tmbundle: - text.html.ftl +vendor/grammars/GeneroFgl.tmbundle: +- source.genero-4gl +- source.genero-per vendor/grammars/Handlebars: - text.html.handlebars vendor/grammars/IDL-Syntax: @@ -389,9 +392,6 @@ vendor/grammars/gemfile-lock-tmlanguage: - source.gemfile-lock vendor/grammars/gemini-vscode: - source.gemini -vendor/grammars/genero.tmbundle: -- source.genero -- source.genero-forms vendor/grammars/gettext.tmbundle: - source.po vendor/grammars/gnuplot-tmbundle: diff --git a/lib/linguist/languages.yml b/lib/linguist/languages.yml index fb067e671b..56a46f463d 100644 --- a/lib/linguist/languages.yml +++ b/lib/linguist/languages.yml @@ -2271,20 +2271,20 @@ Gemini: wrap: true tm_scope: source.gemini language_id: 310828396 -Genero: +Genero 4gl: type: programming color: "#63408e" extensions: - ".4gl" - tm_scope: source.genero + tm_scope: source.genero-4gl ace_mode: text language_id: 986054050 -Genero Forms: +Genero per: type: markup color: "#d8df39" extensions: - ".per" - tm_scope: source.genero-forms + tm_scope: source.genero-per ace_mode: text language_id: 902995658 Genie: diff --git a/samples/Genero 4gl/books1.4gl b/samples/Genero 4gl/books1.4gl new file mode 100644 index 0000000000..dd02ba309d --- /dev/null +++ b/samples/Genero 4gl/books1.4gl @@ -0,0 +1,183 @@ +-- To test the sample: +-- +-- $ sed -n 's/\#\# \(.*\)/\1/p' books1.4gl > library.sch +-- $ fglform -M ../"Genero Forms"/books1.per +-- $ mv ../"Genero Forms"/books1.42f . +-- $ fglcomp -M books1.4gl +-- $ fglrun books1.42m +-- + +SCHEMA library + +PUBLIC TYPE t_book RECORD LIKE book.* +PUBLIC TYPE t_book_array DYNAMIC ARRAY OF t_book + +PRIVATE CONSTANT ID_UNKNOWN = 100 + +MAIN + + DEFINE books t_book_array + DEFINE brec t_book + DEFINE f_plot LIKE book.b_plot + + CONNECT TO ":memory:+driver='dbmsqt'" + + CALL create_tables() + + OPEN FORM f1 FROM "books1" + DISPLAY FORM f1 + + CALL fill_book_array(books) + + DIALOG ATTRIBUTES(UNBUFFERED) + + DISPLAY ARRAY books TO sr1.* + + BEFORE ROW + LET f_plot = books[ arr_curr() ].b_plot + + ON ACTION nbrows ATTRIBUTES(TEXT="Row count") + MESSAGE SFMT("Number of books: %1",books.getLength()) + + ON INSERT + LET f_plot = NULL + INITIALIZE brec.* TO NULL + LET brec.b_author = ID_UNKNOWN + LET brec.b_pub_date = TODAY + LET brec.b_price = 0 + CLEAR formonly.f_plot + INPUT brec.* FROM sr1[ scr_line() ].* + ATTRIBUTES(WITHOUT DEFAULTS); + IF NOT int_flag THEN + TRY + INSERT INTO book VALUES brec.* + LET brec.book_id = sqlca.sqlerrd[2] + LET books[ DIALOG.getCurrentRow("sr1") ] = brec + MESSAGE SFMT("New book record created (id=%1)",brec.book_id) + CATCH + ERROR "Could not insert new book row into database:", SQLERRMESSAGE + END TRY + END IF + + ON DELETE + IF mbox_yn("Delete the current row?") THEN + TRY + DELETE FROM book WHERE book_id = books[arr_curr()].book_id + MESSAGE "Book record was deleted" + CATCH + ERROR "Could not delete the book row from database:", SQLERRMESSAGE + END TRY + END IF + + END DISPLAY + + INPUT BY NAME f_plot + + ON ACTION clear_plot ATTRIBUTES(TEXT="Clear") + IF NOT mbox_yn("Are you sure you want to clear the plot summary?") THEN + CONTINUE DIALOG + END IF + LET f_plot = NULL + LET books[ arr_curr() ].b_plot = NULL + UPDATE book SET b_plot = NULL + WHERE book_id = books[ arr_curr() ].book_id + + ON ACTION update_plot ATTRIBUTES(TEXT="Save") + LET books[ arr_curr() ].b_plot = f_plot + UPDATE book SET b_plot = f_plot + WHERE book_id = books[ arr_curr() ].book_id + MESSAGE SFMT("Plot summary saved (%1)",CURRENT HOUR TO SECOND) + + END INPUT + + ON ACTION close + ACCEPT DIALOG + + END DIALOG + +END MAIN + +PRIVATE FUNCTION mbox_yn(question STRING) RETURNS BOOLEAN + DEFINE r BOOLEAN + MENU "Books" ATTRIBUTES(STYLE="dialog", COMMENT=question) + COMMAND "Yes" LET r = TRUE + COMMAND "No" LET r = FALSE + END MENU + RETURN r +END FUNCTION + +FUNCTION fill_book_array(ba t_book_array) + RETURNS () + + DEFINE x INTEGER + + DECLARE c1 CURSOR FOR + SELECT * FROM book ORDER BY b_title + + LET x = 1 + FOREACH c1 INTO ba[x].* + LET x = x + 1 + END FOREACH + CALL ba.deleteElement(x) + +END FUNCTION + +FUNCTION init_authors(e ui.ComboBox) + RETURNS () + + DEFINE id LIKE author.auth_id + DEFINE name LIKE author.a_name + + DECLARE c2 CURSOR FOR + SELECT auth_id, a_name FROM author ORDER BY a_name + + FOREACH c2 INTO id, name + CALL e.addItem( id, name ) + END FOREACH + +END FUNCTION + +FUNCTION create_tables() + RETURNS () + + CREATE TABLE author ( + auth_id SERIAL NOT NULL PRIMARY KEY, + a_name VARCHAR(50) + ); + + CREATE TABLE book ( + book_id SERIAL NOT NULL PRIMARY KEY, + b_title VARCHAR(100) NOT NULL, + b_author INTEGER NOT NULL REFERENCES author(auth_id), + b_isbn VARCHAR(20) NOT NULL UNIQUE, + b_pub_date DATE, + b_price DECIMAL(10,2), + b_plot VARCHAR(500) + ); + + INSERT INTO author VALUES ( 100, '?UNDEFINED?' ); + + INSERT INTO author VALUES ( 101, 'Stephen KING' ); + INSERT INTO book VALUES ( 10101, 'The Talisman', 101, '978-0-670-69199-9', '1984-11-08', 15.60, NULL ); + INSERT INTO book VALUES ( 10102, 'Doctor Sleep', 101, '978-1-4767-2765-3', '2013-09-24', 12.00, NULL ); + INSERT INTO book VALUES ( 10103, 'The Long Walk', 101, '978-0-451-08754-6', '1979-07-11', 14.30, NULL ); + + INSERT INTO author VALUES ( 103, 'Dan Brown' ); + INSERT INTO book VALUES ( 10301, 'Digital Fortress', 103, '0-312-18087-X', '1998-01-01', 10.20, NULL ); + INSERT INTO book VALUES ( 10302, 'Angels & Demons', 103, '0-671-02735-2 ', '2000-04-01', 14.55, NULL ); + + -- For PostgreSQL + -- SELECT setval( pg_get_serial_sequence('author','auth_id'), 200 ); + -- SELECT setval( pg_get_serial_sequence('book','book_id'), 20000 ); + +END FUNCTION + +## author^auth_id^262^4^1^ +## author^a_name^201^50^2^ +## book^book_id^262^4^1^ +## book^b_title^457^100^2^ +## book^b_author^258^4^3^ +## book^b_isbn^457^20^4^ +## book^b_pub_date^7^4^5^ +## book^b_price^5^2562^6^ +## book^b_plot^201^500^7^ diff --git a/samples/Genero 4gl/webserv1.4gl b/samples/Genero 4gl/webserv1.4gl new file mode 100644 index 0000000000..a2863e19ce --- /dev/null +++ b/samples/Genero 4gl/webserv1.4gl @@ -0,0 +1,75 @@ +-- Testing the web service: +-- +-- Define FGLAPPSERVER to a free TCP port: +-- $ export FGLAPPSERVER=8089 +-- +-- Compile and start the server program: +-- $ fglcomp WebService.4gl +-- $ fglrun WebService.42m +-- +-- Open a browser, and fetch the OpenAPI doc with: +-- +-- http://localhost:8089/api?openapi.json +-- + +OPTIONS SHORT CIRCUIT + +IMPORT com +IMPORT FGL webserv1_api + +MAIN + + DEFER INTERRUPT + CALL startServer() + +END MAIN + +PRIVATE FUNCTION startServer() RETURNS() + DEFINE returnCode INTEGER + + CALL com.WebServiceEngine.RegisterRestService("webserv_api", "api") + + DISPLAY "Server started" + + CALL com.WebServiceEngine.Start() + + LET int_flag = FALSE + WHILE TRUE + LET returnCode = com.WebServiceEngine.ProcessServices(-1) + CASE returnCode + WHEN 0 + DISPLAY "Request processed." + WHEN -1 + DISPLAY "Timeout reached." + WHEN -2 + DISPLAY "Disconnected from application server." + # the application server has closed the connection + EXIT PROGRAM + WHEN -3 + DISPLAY "Client connection lost." + WHEN -4 + DISPLAY "Server interrupted with ctrl-c." + WHEN -9 + DISPLAY "Unsupported operation." + WHEN -10 + DISPLAY "Internal server error." + WHEN -23 + DISPLAY "Deserialization error." + WHEN -35 + DISPLAY "No such REST operation found." + WHEN -36 + DISPLAY "Missing REST parameter." + OTHERWISE + DISPLAY SFMT("Unexpected server error: %1",returnCode) + EXIT WHILE + END CASE + + IF int_flag THEN + EXIT WHILE + END IF + + END WHILE + + DISPLAY "Server stopped" + +END FUNCTION diff --git a/samples/Genero 4gl/webserv1_api.4gl b/samples/Genero 4gl/webserv1_api.4gl new file mode 100644 index 0000000000..b0aea4fcfe --- /dev/null +++ b/samples/Genero 4gl/webserv1_api.4gl @@ -0,0 +1,45 @@ +OPTIONS SHORT CIRCUIT + +IMPORT com + +PUBLIC TYPE UserAccount RECORD + id INTEGER, + name STRING, + dob DATE, + isActive BOOLEAN +END RECORD + +PUBLIC DEFINE userError RECORD ATTRIBUTE(WSError = "User error") + message STRING +END RECORD + +PUBLIC FUNCTION getNumberUsers() + ATTRIBUTES(WSGet, + WSPath = "/users/count", + WSDescription = "Returns a count of users.") + RETURNS INTEGER + + DEFINE returnCount INTEGER + SELECT COUNT(*) INTO returnCount FROM UserAccounts + RETURN returnCount + +END FUNCTION + +PUBLIC FUNCTION createUser(newUser UserAccount) + ATTRIBUTES(WSPost, + WSPath = "/users", + WSDescription = "Create a user profile", + WSThrows = "400:@userError") + RETURNS STRING + + DEFINE returnMessage STRING + TRY + INSERT INTO UserAccounts VALUES (newUser.*) + LET returnMessage = SFMT("Created user: %1", newUser.name) + CATCH + LET userError.message = SFMT("SQL error:%1 [%2]", sqlca.sqlcode, SQLERRMESSAGE) + CALL com.WebServiceEngine.SetRestError(400, userError) + END TRY + RETURN returnMessage + +END FUNCTION diff --git a/samples/Genero Forms/FormProgram.per b/samples/Genero Forms/FormProgram.per deleted file mode 100644 index e0a7827b9a..0000000000 --- a/samples/Genero Forms/FormProgram.per +++ /dev/null @@ -1,17 +0,0 @@ -LAYOUT - VBOX - GROUP group1 (text = "Edit") - HBOX - GRID -{ - [edit_field ] -} - END - END - END - END -END - -ATTRIBUTES -EDIT edit_field = formonly.edit_field; -END \ No newline at end of file diff --git a/samples/Genero per/books1.per b/samples/Genero per/books1.per new file mode 100644 index 0000000000..59648cf2a3 --- /dev/null +++ b/samples/Genero per/books1.per @@ -0,0 +1,38 @@ +SCHEMA library + +LAYOUT +HBOX ( ORIENTATION@SMALL = VERTICAL ) +TABLE +{ +[c1 |c2 |c3 |c4 |c5 ] +} +END +GRID +{ +Plot +[f1 ] +[ ] +[ ] +} +END +END +END + +TABLES +book +END + +ATTRIBUTES + PHANTOM book.book_id; + EDIT c1 = book.b_title, TITLE="Name", SCROLL; +COMBOBOX c2 = book.b_author, TITLE="Author", INITIALIZER=init_authors; + EDIT c3 = book.b_isbn, TITLE="ISBN", SCROLL; +DATEEDIT c4 = book.b_pub_date, TITLE="Publication"; + EDIT c5 = book.b_price, TITLE="Price"; +TEXTEDIT f1 = FORMONLY.f_plot, STRETCH=BOTH; + PHANTOM book.b_plot; +END + +INSTRUCTIONS +SCREEN RECORD sr1(book.*); +END diff --git a/samples/Genero/FormProgram.4gl b/samples/Genero/FormProgram.4gl deleted file mode 100644 index 67610032ef..0000000000 --- a/samples/Genero/FormProgram.4gl +++ /dev/null @@ -1,60 +0,0 @@ -options short circuit - -private define - mv_screenClosed smallint - -main - define - lv_windowTitle string, - lv_windowRoot ui.Window, - edit_field string - - let lv_windowTitle = "Example Form Program" - - # open window - open window w with form "FormProgram" - - call closeDefaultScreen() - # get the window root and set the title - let lv_windowRoot = ui.Window.getCurrent() - if (lv_windowRoot is not null) then - call lv_windowRoot.setText(lv_windowTitle) - end if - - input by name edit_field - - on action accept - exit input - - on action cancel - exit input - - on action close - exit input - - end input - - close window w - -end main - -private function closeDefaultScreen() - define - lv_uiRoot om.DomNode, - lv_nodeList om.NodeList, - lv_nodeListCount smallint - - if (mv_screenClosed is null) or (not mv_screenClosed) then - let lv_uiRoot = ui.Interface.getRootNode() - if (lv_uiRoot is not null) then - let lv_nodeList = lv_uiRoot.selectByPath("//Window[@name=\"screen\"]") - let lv_nodeListCount = lv_nodeList.getLength() - - if (lv_nodeListCount > 0) then - close window screen - let mv_screenClosed = TRUE - end if - end if - end if - -end function \ No newline at end of file diff --git a/samples/Genero/WebService.4gl b/samples/Genero/WebService.4gl deleted file mode 100644 index 9219718bb7..0000000000 --- a/samples/Genero/WebService.4gl +++ /dev/null @@ -1,61 +0,0 @@ -options short circuit - -import com -import fgl WebService_api - -main - - call startServer() - -end main - -private function startServer() returns () - define - returnCode integer - - call com.WebServiceEngine.RegisterRestService("WebService_api", "api") - - display "Server started" - - call com.WebServiceEngine.Start() - - while true - let returnCode = com.WebServiceEngine.ProcessServices(-1) - case returnCode - when 0 - display "Request processed." - when -1 - display "Timeout reached." - when -2 - display "Disconnected from application server." - # the application server has closed the connection - exit program - when -3 - display "Client connection lost." - when -4 - display "Server interrupted with ctrl-c." - when -9 - display "Unsupported operation." - when -10 - display "Internal server error." - when -23 - display "Deserialization error." - when -35 - display "No such REST operation found." - when -36 - display "Missing REST parameter." - otherwise - display "Unexpected server error " || returnCode || "." - exit while - end case - - if int_flag != 0 then - let int_flag = 0 - exit while - end if - - end while - - display "Server stopped" - -end function \ No newline at end of file diff --git a/samples/Genero/WebService_api.4gl b/samples/Genero/WebService_api.4gl deleted file mode 100644 index 2ceba06a30..0000000000 --- a/samples/Genero/WebService_api.4gl +++ /dev/null @@ -1,48 +0,0 @@ - - -options short circuit - -import com - -public type UserAccount record - id integer, - name string, - dob date, - isActive boolean -end record - -public define userError record attribute(WSError="User error") - message string -end record - -public function getNumberUsers() -attributes(WSGet, WSPath="/users/count", WSDescription="Returns a count of users.") -returns (integer) - define - returnCount integer - - SELECT COUNT(*) INTO returnCount FROM UserAccounts - - return returnCount -end function - -public function createUser(newUser UserAccount) -attributes(WSPost, WSPath="/users", WSDescription="Create a user profile", WSThrows="400:@userError") -returns string - define - returnMessage string - - whenever error continue - INSERT INTO UserAccounts VALUES (newUser.*) - whenever error stop - - case - when sqlca.sqlcode == 0 - let returnMessage = sfmt("Created user: %1", newUser.name) - otherwise - let userError.message = sfmt("SQL error:% 1 [%2]", sqlca.sqlcode, SQLERRMESSAGE) - call com.WebServiceEngine.SetRestError(400, userError) - end case - - return returnMessage -end function \ No newline at end of file diff --git a/vendor/README.md b/vendor/README.md index fcd7df2f7a..456e19f9d6 100644 --- a/vendor/README.md +++ b/vendor/README.md @@ -191,8 +191,8 @@ This is a list of grammars that Linguist selects to provide syntax highlighting - **Game Maker Language:** [textmate/c.tmbundle](https://github.com/textmate/c.tmbundle) - **Gemfile.lock:** [hmarr/gemfile-lock-tmlanguage](https://github.com/hmarr/gemfile-lock-tmlanguage) - **Gemini:** [printfn/gemini-vscode](https://github.com/printfn/gemini-vscode) -- **Genero:** [alienriver49/genero.tmbundle](https://github.com/alienriver49/genero.tmbundle) -- **Genero Forms:** [alienriver49/genero.tmbundle](https://github.com/alienriver49/genero.tmbundle) +- **Genero 4gl:** [FourjsGenero/GeneroFgl.tmbundle](https://github.com/FourjsGenero/GeneroFgl.tmbundle) +- **Genero per:** [FourjsGenero/GeneroFgl.tmbundle](https://github.com/FourjsGenero/GeneroFgl.tmbundle) - **Genshi:** [genshi.edgewall.org/query](https://genshi.edgewall.org/query) - **Gentoo Ebuild:** [atom/language-shellscript](https://github.com/atom/language-shellscript) - **Gentoo Eclass:** [atom/language-shellscript](https://github.com/atom/language-shellscript) diff --git a/vendor/grammars/GeneroFgl.tmbundle b/vendor/grammars/GeneroFgl.tmbundle new file mode 160000 index 0000000000..08c18d5226 --- /dev/null +++ b/vendor/grammars/GeneroFgl.tmbundle @@ -0,0 +1 @@ +Subproject commit 08c18d5226822a1ebdc21d3f8454a12c19e080ae diff --git a/vendor/grammars/genero.tmbundle b/vendor/grammars/genero.tmbundle deleted file mode 160000 index ea111e21c5..0000000000 --- a/vendor/grammars/genero.tmbundle +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ea111e21c5424b09330197696428cfe1dee65df4 diff --git a/vendor/licenses/git_submodule/GeneroFgl.tmbundle.dep.yml b/vendor/licenses/git_submodule/GeneroFgl.tmbundle.dep.yml new file mode 100644 index 0000000000..7e09e19f96 --- /dev/null +++ b/vendor/licenses/git_submodule/GeneroFgl.tmbundle.dep.yml @@ -0,0 +1,19 @@ +--- +name: GeneroFgl.tmbundle +version: '08c18d5226822a1ebdc21d3f8454a12c19e080ae' +type: git_submodule +homepage: https://github.com/FourjsGenero/GeneroFgl.tmbundle +license: unlicense +licenses: +- sources: LICENSE.txt + text: |- + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. + + In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to +notices: [] diff --git a/vendor/licenses/git_submodule/genero.tmbundle.dep.yml b/vendor/licenses/git_submodule/genero.tmbundle.dep.yml deleted file mode 100644 index f897677c5e..0000000000 --- a/vendor/licenses/git_submodule/genero.tmbundle.dep.yml +++ /dev/null @@ -1,32 +0,0 @@ ---- -name: genero.tmbundle -version: ea111e21c5424b09330197696428cfe1dee65df4 -type: git_submodule -homepage: https://github.com/alienriver49/genero.tmbundle -license: mit -licenses: -- sources: LICENSE - text: | - MIT License - - Copyright (c) 2020 Brian Jackson, Nick Huot, Munis Architecture Development - Team, Tyler Technologies - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -notices: []